Serveur de Messagerie ldap postfix dovecot rspamd fail2ban

Première partie du tutoriel complet sur l’installation d’un serveur mail. Nous allons y voir la mise en place d’un serveur LDAP destiné à stocker les informations nécessaires au bon fonctionnement de notre serveur de messagerie.

Jusqu’à présent, pour mon serveur de messagerie, je passais par un stockage des comptes dans une base SQL. Ayant mis en place un serveur LDAP, j’ai voulu greffer ma messagerie dessus.

Il faut savoir qu’il n’y a pas une façon unique de faire. Les infos peuvent être organisées autrement, par exemple, les comptes utilisateurs peuvent être dans l’OU mail et différents des comptes présents dans l’OU people. Ou au contraire, on peut rassembler les infos de chaque domaine dans son OU.

L’important au final étant que vos requêtes Ldap puissent sortir les infos, à savoir : les domaines gérés, les alias et les comptes utilisateurs.

Mon modèle n’est pas forcement le plus simple ou le plus adapté à votre cas, mais le changer ne demande que peu d’efforts, l’important étant surtout de comprendre la logique.

Table des matières

Serveur de Messagerie ldap postfix dovecot rspamd fail2ban

LDAP

I – Installation

II – Rapide configuration

A – Mdp Admin dans un fichier

B – Droits d’accès à la configuration du serveur

C – Compte Viewer

D – Des alias

II – Peuplement de base

III – Explication de l’organisation LDAP

IV – Mise en place

A – Le Schéma

B – Les OUs pour nos domaines

C – Les Alias

D – Les nouveaux attributs des utilisateurs

V – Conclusion

Postfix

I – Préparatifs

A – Une nouvelle IP

B – DNS

C – Routeur

II – Les ports dans le domaine du mail

III – Installation

IV – Certificat

V – Postfix

A – La base

B – Le Ldap

C – Alias locaux

IV – Conclusion

Dovecot

I – La base

A – Utilisateur Vmail

B – Du ménage

C – De la config

1 – Fichier 10-auth.conf

2 – Fichier 10-logging.conf

3 – Fichier 10-mail.conf

4 – Fichier 10-master.conf

5 – Fichier 10-ssl.conf

6 – Fichier 15-mailboxes.conf

7 – Fichier 20-imap.conf

8 – Fichier 20-lmtp.conf

9 – Fichier 20-managesieve.conf

10 – Fichier 90-sieve.conf

II – Fichiers de mapping Ldap

A – Selon la Doc de Dovecot

B – Passdb et Userdb

C – Bind Ldap

1 – auth_bind = yes

2 – auth_bind = no

D – Paf

E – Solution

III – Sieve

1 – La base

2 – Niveau Utilisateur

3 – Tests

IV – Quota

A – Configuration

B – Avertissement automatique

C – Tests

V – Conclusion

Optimisation de Postfix

I – Sécurisation SMTPS et Submission

II – Antiforge

A – Explication

B – Pour le fun

III – Contrôle d’accès

A – check_client_access

B – check_helo_access

C – check_recipient_access

D – check_sender_access

IV – Les « Header Checks »

A – Filtrage des fichiers à risque

B – Supprimer les informations sensibles

C – Oui mais…

V – Conclusion

Policyd SPF et Postscreen

I – Policyd SPF

II – Postcreen

A – Activation

B – Configuration

1 – Contrôles simples

a – Access list

b – Greet banner

c – Dnsbl

2 – Contrôle profond

a – Pipelining

b – Non SMTP Command

c – Bare Newline

III – Conclusion

Rspamd

I – Installation

II – Configuration

A – Assistant

B – Quelques ajustements

1 – classifier-bayes.conf

2 – worker-controller.inc

3  – metrics.conf

4 – milter_headers.conf

5 – rspamd_update.conf

III – Liaison avec Postfix

IV – Apprentissage

V – Apprentissage par déplacement.

VI – Signature DKIM

A – Configuration

B – Signature d’un domaine

VII – Interface Web

VIII – Conclusion

DKIM, SPF et DMARC

I – SPF

II – DKIM

III – DMARC

IV – Tests

V – Conclusion

Conclusion

I – Filtre Sieve

II – DNSBL

III – Liens

IV – Articles à venir

Fail2ban, configuration pour Postfix et Dovecot

I – Présentation et installation

II – Configuration

A – Postfix

B – Dovecot

IV – Test

V – Conclusion

Fail2ban et python pour piloter un Firewall central

II – Sur le routeur

A – De nouvelles chaines

B – Serveur Python

C – Service

II – Sur le serveur

A – Client python

B – Fail2ban

1 – Action

2 – Jail

III – Test

iV – Conclusion

 

LDAP

I – Installation

Pour le serveur LDAP,  je pars sur une VM fraîchement installée puis une mise à jour et on installe le paquet slapd et le paquet ldap-utils contenant les outils pour modifier le Ldap.

# apt-get update && apt-get upgrade

# apt-get install slapd ldap-utils

On reconfigure le paquet :

# dpkg-reconfigure slapd

La, vous répondez comme cela :

Omit OpenLDAP server configuration? No

DNS domain name: debugo.fr

Organization name? Debugo

Administrator password: PASSWORD

Confirm password: PASSWORD

Database backend to use: MDB

Do you want the database to be removed when slapd is purged? YES

Ensuite, un petit tour dans le fichier /etc/ldap/ldap.conf pour le configurer comme il faut (utilisé par les outils ldap pour modifier le LDAP en ligne de commande) :

BASE dc=debugo,dc=fr

URI ldap://IP.MACHINE/

On relance openldap :

# service slapd restart

On test avec :

# ldapsearch -xLLL

II – Rapide configuration

Avant tout, on va créer des répertoires pour stocker nos fichiers :

# mkdir /root/ldap

# cd /root/ldap

A – Mdp Admin dans un fichier

Afin d’éviter d’avoir à toujours retaper le mot de passe admin lors des commandes, nous allons l’enregistrer dans un fichier.

On va créer un fichier /root/pwdldap et mettre le mot de passe dedans :

# echo -n "mdpadmin" > /root/pwdldap

# chmod 600 /root/pwdldap

On test :

# ldapsearch -x -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b dc=debugo,dc=fr

B – Droits d’accès à la configuration du serveur

Par défaut, l’accès à la configuration n’est pas possible en passant par le socket réseau avec le compte admin (et on en aura besoin pour ajouter notre schéma).
Créez le fichier LDIF /root/ldap/acces-conf-admin.ldif, et insérez :

dn: olcDatabase={0}config,cn=config

changeType: modify

add: olcAccess

olcAccess: to * by dn.exact=cn=admin,dc=debugo,dc=fr manage by * break

Injectez :

# cd /root/ldap

# ldapmodify -Y external -H ldapi:/// -f acces-conf-admin.ldif

Et l’on peut voir que c’est bon avec :

# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b cn=config

C – Compte Viewer

On va ajouter notre compte système viewer dans un fichier viewer.ldif. Ce compte servira à Postfix et Dovecot, pour qu’ils puissent lire les infos du Ldap.

dn: cn=viewer,ou=system,dc=debugo,dc=fr

objectClass: simpleSecurityObject

objectClass: organizationalRole

cn: viewer

description: LDAP viewer

userPassword: passview

Et on l’injecte :

# ladd  -f viewer.ldif

Puis on va modifier les Acls afin de donner le droit au compte viewer de lire les passwords.

Fichier acl.ldif :

dn: olcDatabase={1}mdb,cn=config

changetype: modify

replace: olcAccess

olcAccess: to attrs=userPassword by self write by anonymous auth by dn="cn=viewer,ou=system,dc=debugo,dc=fr" read by dn="cn=admin,dc=debugo,dc=fr" write by * none

olcAccess: to dn.base="dc=debugo,dc=fr" by users read

olcAccess: to * by self write by dn="cn=admin,dc=debugo,dc=fr" write by * read by anonymous none

On injecte :

# ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f acl.ldif

 

D – Des alias

Nous allons utiliser énormément les commande fournies par ldap-utils. Du coup, afin d’aller plus vite nous allons créer des alias.

Éditez le fichier /root/.bashrc pour y ajouter :

alias lmodif='ldapmodify -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap'

alias lsearch='ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap'

alias ladd='ldapadd -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap'

alias ldel='ldapdelete -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap'

Pour une prise en compte immédiate :

# source /root/.bashrc

Je ne fais qu’effleurer la configuration d’un serveur LDAP. Pour plus de détails, je vous invite fortement à consulter ma série d’articles sur le Ldap.

II – Peuplement de base

On va créer nos OUs de base dans un fichier ou.ldif :

dn: ou=people,dc=debugo,dc=fr

ou: people

objectClass: organizationalUnit

 

dn: ou=system,dc=debugo,dc=fr

ou: people

objectClass: organizationalUnit

Et on l’injecte :

# ladd -f ou.ldif

 

Avant de passer à la création de nos utilisateurs, petit point sur le stockage des mots de passe dans LDAP.

Par défaut, ils sont stockés en clair. Dans la suite du tutoriel, cela pose soucis avec le bind de Dovecot. Puis stocker en clair, c’est pas top.

Il est possible de force le hash avec l’overlay Ppolicy. A vous de configurer cela si vous voulez.

Sinon, à la main :

# slappasswd -h {SSHA}

Renseignez le pass deux fois et vous obtiendrez le hash en SSHA, hash qu’il faudra mettre dans le champ userPassword.

Puis nous passons à un premier utilisateur dans un fichier usertoto.ldif :

dn: uid=toto,ou=people,dc=debugo,dc=fr

objectclass: person

objectclass: organizationalPerson

objectclass: inetOrgPerson

uid: toto

sn: toto

givenName: toto

cn: toto

displayName: toto

userPassword: {SSHA}.....

mail: toto@domaine1.fr

et un second dans un fichier usertata.ldif :

dn: uid=tata,ou=people,dc=debugo,dc=fr

objectclass: person

objectclass: organizationalPerson

objectclass: inetOrgPerson

uid: tata

sn: tata

givenName: tata

cn: tata

displayName: tata

userPassword: {SSHA}.....

mail: tata@domaine1.fr

Pour terminer en injectant les deux :

# ladd -f usertoto.ldif

# ladd -f usertata.ldif

III – Explication de l’organisation LDAP

Jusque la, je stocke mes comptes utilisateur. Ceci dit, il me manque des attributs, que je rajouterais via un schéma personnel.

Au niveau domaine, j’en ai deux : domaine1.fr, domaine2.fr et je gère deux compte mails toto@domaine1.fr et tata@domaine1.fr. Toutes les autres adresses de domaine1 et domaine2 (par ex ccc@domaine1.fr, aaa@domaine2.fr, bbb@domaine2.fr, etc.. seront renvoyés soit vers toto@domaine1.fr soit vers tata@domaine1.fr.

Pour la gestion domaines et alias, j’ai donc choisi de faire de la sorte :

dc=debugo,dc=fr

    ou=people,dc=debugo,dc=fr

        "Stockage de mes utilisateurs"

    ou=mail,dc=debugo,dc=fr

        ou=domaine1.fr,

            cn=alias1@domaine1.fr,ou=domaine1.fr,ou=mail,dc=debugo,dc=fr

                attr: mailfrom: alias@domaine1.fr

                attr: mailto: toto@domaine1.fr

            etc...

        ou=domaine2.fr,

            etc...

Chaque domaine sera une OU dans une nouvelle OU créée pour l’occasion.

Et dans chaque OU, je crée des entrées correspondants aux alias, la aussi avec l’aide de schéma supplémentaire

Mes domaines auraient très bien pu être non pas des OU mais des entrées, au niveau de l’OU mail et les alias définies par des attributs soit dans ces entrées soit dans les entrées des users. Je vous le disais, on peut vraiment faire comme on veut.

 

IV – Mise en place

A – Le Schéma

On va créer un fichier schema.ldif :

dn: cn=maildebugo,cn=schema,cn=config

objectClass: olcSchemaConfig

cn: maildebugo

olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.20 NAME 'mailaccountquota' DESC 'Quota Mail' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.21 NAME 'mailaccountactif' DESC 'Mail Actif' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.40 NAME 'mailaliasfrom' DESC 'Mail From' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.41 NAME 'mailaliasto' DESC 'Mail To' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.42 NAME 'mailaliasactif' DESC 'Alias Actif' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.60 NAME 'maildomain' DESC 'Domaine' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.61 NAME 'maildomainactif' DESC 'Domaine Actif' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

olcObjectClasses: ( 1.3.6.1.4.1.99999.2.1.20 NAME 'mailaccountdebugo' SUP TOP AUXILIARY MUST ( mailaccountquota $ mailaccountactif))

olcObjectClasses: ( 1.3.6.1.4.1.99999.2.1.40 NAME 'mailaliasdebugo' SUP TOP STRUCTURAL MUST ( cn $ mailaliasfrom $ mailaliasto $ mailaliasactif))

olcObjectClasses: ( 1.3.6.1.4.1.99999.2.1.60 NAME 'maildomaindebugo' SUP TOP AUXILIARY MUST ( maildomain $ maildomainactif))

Vous voyez trois séries de chiffres dans le fichier.
L’OID 1.3.6.1.4.1.99999.2.2.x correspond à la hiérarchie de mes attributs (la branche 1.3.6.1.4.1 est la branche dédiée aux OID privés :
voir ici).
Le 99999 devrait être dans l’idéal remplacé par le PEN que vous pouvez obtenir sur cette page. Si vous ne destinez pas votre schéma a être public, ça n’a pas trop d’importance, mais attention à ne pas prendre un numéro déjà existant si un jour vous importez un schéma avec ce numéro, bref, vous voyez le topo. J’ai fais la demande, j’ai eu mon PEN en 72h je crois…
L’OID 1.3.6.1.4.1.99999.2.1.x est sur le même modèle mais définit un objet.
L’OID 1.3.6.1.4.1.1466.115.121.1.15 correspond à la définition d’une directory string (chaîne de caractère), je fais simple et prend ce type de donnée pour mes nouveau attributs.

Ce schéma est au final assez simple, je rajoute trois nouvelles classe d’objets : mailaccountdebugo, maildomaindebugo et mailaliasdebugo (qui à la particularité d’être structural, c’est à dire que ce pourra être une entrée sans ajout d’autre classe (par ex, inetogperson, etc…).
Chaque classe possède des attributs obligatoire (MUST).

L’attribut mailaliasto est le seule à ne pas avoir SINGLE-VALUE, en effet, un alias peut renvoyer vers plusieurs bals.

Le puriste et fin connaisseur des schémas de base d’OpenLdap me dira : « Oui, on peut faire tout ça sans rajouter de nouveaux schémas, en utilisant des attributs qui existent déjà ! »

Oui, mais dans mon cas, cela ne me convenait pas (les alias dans l’entrée de l’user, pourquoi pas, mais pour ensuite dire s’ils sont actifs, etc.., c’est compliqué). Et puis c’est l’occasion de faire des manipulations sur le Ldap…

Bref, on va ajouter notre schéma :

# ladd -f schema.ldif

 

B – Les OUs pour nos domaines

Ensuite, on va créer nos nouvelles OUs dans un fichier oumail.ldif :

dn: ou=mail,dc=debugo,dc=fr

ou: people

objectClass: organizationalUnit

 

dn: ou=domaine1.fr,ou=mail,dc=debugo,dc=fr

ou: domaine1.fr

objectClass: organizationalUnit

objectClass: maildomaindebugo

description: Domaine mail primaire

maildomain: domaine1.fr

maildomainactif: YES

 

dn: ou=domaine2.fr,ou=mail,dc=debugo,dc=fr

ou: domaine2.fr

objectClass: organizationalUnit

objectClass: maildomaindebugo

description: Domaine mail secondaire

maildomain: domaine2.fr

maildomainactif: YES

On injecte :

# ladd -f oumail.ldif

 

C – Les Alias

Puis on passe à la création des entrées pour les alias dans un fichier alias.ldif :

dn: cn=postmaster@domaine1.fr,ou=domaine1.fr,ou=mail,dc=debugo,dc=fr

objectclass: mailaliasdebugo

cn: postmaster@domaine1.fr

mailaliasfrom: postmaster@domaine1.fr

mailaliasto: toto@domaine1.fr

mailaliasactif: YES

 

dn: cn=postmaster@domaine2.fr,ou=domaine2.fr,ou=mail,dc=debugo,dc=fr

objectclass: mailaliasdebugo

cn: postmaster@domaine2.fr

mailaliasfrom: postmaster@domaine2.fr

mailaliasto: toto@domaine1.fr

mailaliasactif: YES

 

dn: cn=testalias@domaine1.fr,ou=domaine1.fr,ou=mail,dc=debugo,dc=fr

objectclass: mailaliasdebugo

cn: testalias@domaine1.fr

mailaliasfrom: testalias@domaine1.fr

mailaliasto: toto@domaine1.fr

mailaliasto: tata@domaine1.fr

mailaliasactif: YES

A vous bien sur de faire vos propres alias en fonction de vos besoins.

On injecte :

# ladd -f alias.ldif

 

D – Les nouveaux attributs des utilisateurs

Et pour finir, on va rajouter les attributs de la classe mailaccountdebugo à nos utilisateurs.

Fichier attrtoto.ldif :

dn: uid=toto,ou=people,dc=shyride,dc=org

changetype: modify

add: objectclass

objectclass: mailaccountdebugo

-

add: mailaccountquota

mailaccountquota: 0

-

add: mailaccountactif

mailaccountactif: YES

Fichier attrtata.ldif :

dn: uid=tata,ou=people,dc=shyride,dc=org

changetype: modify

add: objectclass

objectclass: mailaccountdebugo

-

add: mailaccountquota

mailaccountquota: 0

-

add: mailaccountactif

mailaccountactif: YES

On injecte ces deux fichiers :

# ladd -f atttoto.ldif

# ladd -f attrtata.ldif

Par la suite, pour ajouter un nouvel utilisateur, on pourra bien évidemment tout faire en un bloc :

dn: uid=new,ou=people,dc=debugo,dc=fr

objectclass: person

objectclass: organizationalPerson

objectclass: inetOrgPerson

objectclass: mailaccountdebugo

uid: new

sn: new

givenName: new

cn: new

displayName: new

userPassword: {SSHA}.....

mail: new@domaine1.fr

mailaccountquota: 0

mailaccountactif: YES

 

V – Conclusion

On peut déjà tester  en listant par exemple les domaines gérés :

# lsearch -b "ou=mail,dc=debugo,dc=fr" "(&(objectClass=maildomaindebugo))"  ou

Ou encore, pour savoir par exemple vers quelle bal renvoie l’alias postmaster@domaine1.fr :

# lsearch -b "ou=mail,dc=debugo,dc=fr" "(&(objectClass=mailaliasdebugo)(mailaliasfrom=postmaster@domaine1.fr))" mailaliasto

Voila qui termine la partie LDAP pour l’utilisation avec un serveur de messagerie. Je vous invite encore une fois à consulter mon tutoriel sur LDAP qui vous expliquera également comment modifier, supprimer des données dans l’annuaire (ainsi que plein d’autres choses ! )

Et sinon, on peut passer à la suite avec la mise en place de Postfix

Postfix

Seconde partie du tutoriel consacré à l’installation d’un serveur de messagerie.

Préalablement, nous avons installé et configuré le serveur Ldap. Dans cette partie, nous allons mettre en place nos certificats et procéder à la configuration de base de Postfix.

I – Préparatifs

Avant de se lancer, il faut faire quelques manipulations.

A – Une nouvelle IP

Au niveau messagerie, si vous voulez que votre serveur puisse envoyer des mails sans que les autres le jette comme un malpropre, il y a un premier point important.

Il est nécessaire que son reverse dns soit correctement configuré : si on demande l’adresse de mail.domaine1.fr et qu’on a XXX.XXX.XXX.XXX, il faut qu’en demandant le reverse de XXX.XXX.XX.XXX on obtienne mail.domaine1.fr

Si vous avez déjà un autre reverse sur l’adresse, soit vous changez, mais bon… Soit vous prenez une nouvelle IP.

Étant chez Online, j’ai donc pris une nouvelle IP Failover ou j’ai configuré le reverse en mail.domaine1.fr.
Ensuite, elle est branché sur ma VM routeur sur le bridge br0 (avec la mac bien renseignée !).

Cette manipulation est identique à ce que je fais dans cet article (au final, mon routeur aura deux IPFO)

 

B – DNS

Sur le serveur dns, on va renseigner les nouveaux enregistrements dans le fichier de zone correspondant :

      IN  MX  10 mail.domaine1.fr

mail  IN  A   IP.FO2

Le champ MX indique qu’il s’agit d’un serveur mail. Et ensuite, on définit simplement l’IP de mail.domaine1.fr.

Si on gère son dns (voir ici), on pense à incrémenter le serial et à recharger avec :

# rndc reload

Pour tester :

# dig domaine1.fr MX +short

C – Routeur

Au niveau de notre routeur, on va indiquer les ports qu’on redirige en entrée :

iptables -t nat -A PREROUTING -d IP.FO2 -p tcp -m multiport --dports 25,80,143,465,587,993,4190 -j DNAT --to-destination ip.interne

iptables -t filter -A FORWARD -p tcp -d ip.interne -m multiport --dports 25,80,143,465,587,993,4190 -j ACCEPT

Et pour terminer, on redirige aussi le port 80 (Web) car pour le certificat Let’s Encrypt, le serveur aura besoin de monter un serveur web temporaire accessible de l’extérieur.

En sortie :

iptables -t filter -A FORWARD -p tcp -s ip.interne -m multiport --dports 25,53,80,443 -j ACCEPT

iptables -t nat -A POSTROUTING -s ip.interne -p tcp -m multiport --dports 25,53,80,443 -j SNAT --to IP.FO2

Juste le port SMTP et les ports Web. Ajoutez aussi le DNS si vous n’avez pas de resolver interne (dans ce cas, corrigez moi ça en suivant ceci )

II – Les ports dans le domaine du mail

On peut dire que la, c’est un peu le boxon…

Nous avons:

A cela se rajoute leurs pendants sécurisés :

Les ports 110 et 143 peuvent voir leur connexion chiffré avec STARTTLS, aussi appelé EXPLICIT SSL/TLS.

Le client se connecte au serveur en non chiffrée et il négocie le chiffrement juste après. Cette phase se produisant au tout début, toutes les infos sont ensuite chiffrées.

Sur les ports 465 et 587, utilisant le chiffrement SSL/TLS, la sécurité est établie dès le début. On parle aussi de IMPLICIT SSL/TLS.

Pour donner une image, en SSL/TLS, on a une conversion normal dans une canal chiffrée et en STARTTLS, on a une conversation chiffrée dans un canal en clair…

Alors pourquoi garder les deux ?

Les RFC recommandent maintenant de tout faire en SSL/TLS (un potentiel Man-in-the-middle est possible en STARTTLS.)

Mais de vieux clients peuvent encore nécessiter la présence des ports avec TLS explicite… Du coup, bah, vous faites comment vous le sentez…

Pour le tuto, j’ai choisie de tout mettre dans la configuration pour vous montrer. Perso, en prod, je pars sur du SSL/TLS.

Pour le port 25, Le STARTTLS est proposé si le MX distant le supporte.

Pour plus de détails sur comment on en est arrivés la, je vous conseille de lire cet article.

 

III – Installation

Sur une nouvelle VM :

# apt-get install postfix postfix-ldap ca-certificates

Lors de l’installation de Postfix, répondez :

Internet Site

mail.domaine1.fr

Pour ca-certificates, il est toujours bon de l’avoir, et il nous sera utile pour l’installation de Rspamd plus tard.

Et on installe dans la foulée Dovecot :

# apt-get install dovecot-core dovecot-imapd dovecot-ldap dovecot-managesieved dovecot-sieve dovecot-lmtpd

A vrai dire, je l’installe de suite car le script de mise à jour du certificat redémarre les services postfix et dovecot , donc autant éviter des erreurs dès le début…

 

IV – Certificat

On va de suite gérer le certificat avec acme.sh (client pour Let’s Encrypt, plus d’informations dans mon article) :

# apt-get install git socat

Installons maintenant acme.sh :

# cd

# mkdir sources

# cd sources/

# git clone https://github.com/Neilpang/acme.sh.git

# cd ./acme.sh

# ./acme.sh --install

On recharge le bash :

# source /root/.bashrc

Et on lance la création du certificat :

# acme.sh --issue -k 4096 --standalone -d mail.domaine1.fr --log

On installe le certificat :

# mkdir /etc/ssl/private/domaine1.fr

# acme.sh --installcert -d mail.domaine1.fr --cert-file /etc/ssl/private/domaine1.fr/cert.pem --key-file /etc/ssl/private/domaine1.fr/key.pem --ca-file /etc/ssl/private/domaine1.fr/ca.pem --fullchain-file /etc/ssl/private/domaine1.fr/fullcert.pem --reloadCmd 'service postfix reload && service dovecot reload'

On génère nos clés DH :

# openssl dhparam -out /etc/ssl/private/domaine1.fr/dh512.pem 512

# openssl dhparam -out /etc/ssl/private/domaine1.fr/dh2048.pem 2048

# chmod 644 /etc/ssl/private/domaine1.fr/dh{512,2048}.pem

La commande installcert met également en place une tache cron pour le renouvellement automatique de votre certificat qui du coup, renouvelle, copie ou il faut et relance, parfait !

V – Postfix

A – La base

On va éditer le fichier /etc/postfix/main.cf pour le mettre à notre sauce :

mynetworks = 10.0.0.0/8

inet_interfaces = all

inet_protocols = ipv4

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)

biff = no

append_dot_mydomain = yes

readme_directory = no

compatibility_level = 2

 

notify_classes = bounce, delay, policy, protocol, resource, software

myhostname = mail.domaine1.fr

mydestination = $myhostname, mail, localhost.localdomain, localhost

myorigin = $myhostname

disable_vrfy_command = yes

strict_rfc821_envelopes = yes

show_user_unknown_table_name = no

message_size_limit = 0

mailbox_size_limit = 0

allow_percent_hack = no

swap_bangpath = no

recipient_delimiter = +

alias_maps = hash:/etc/aliases

alias_database = hash:/etc/aliases

 

broken_sasl_auth_clients=yes

 

smtp_tls_security_level = may

smtp_tls_session_cache_database  = btree:${data_directory}/smtp_tlscache

 

smtpd_tls_loglevel = 1

smtpd_tls_security_level = may

smtpd_tls_auth_only = yes

smtpd_tls_key_file = /etc/ssl/private/domaine1.fr/key.pem

smtpd_tls_cert_file = /etc/ssl/private/domaine1.fr/cert.pem

smtpd_tls_CAfile = /etc/ssl/private/domaine1.fr/fullcert.pem

smtpd_tls_protocols = !SSLv2 !SSLv3

smtpd_tls_mandatory_protocols = !SSLv2 !SSLv3

smtpd_tls_mandatory_ciphers = high

smtpd_tls_eecdh_grade = strong

smtpd_tls_dh512_param_file  = /etc/ssl/private/domaine1.fr/dh512.pem

smtpd_tls_dh1024_param_file = /etc/ssl/private/domaine1.fr/dh2048.pem

smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_tlscache

smtpd_tls_session_cache_timeout = 3600s

smtpd_tls_received_header = yes

 

smtpd_sasl_auth_enable = yes

smtpd_sasl_path = private/auth

smtpd_sasl_type = dovecot

smtpd_sasl_security_options = noanonymous, noplaintext

smtpd_sasl_tls_security_options = noanonymous

 

tls_preempt_cipherlist = yes

tls_high_cipherlist = ALL EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !MEDIUM !3DES !MD5 !EXP !PSK !SRP !DSS !RC4

tls_ssl_options = no_ticket, no_compression

smtpd_helo_required = yes

 

smtpd_client_restrictions =

    permit_mynetworks,

    permit_sasl_authenticated,

    reject_unknown_reverse_client_hostname,

    reject_unauth_pipelining

 

smtpd_helo_restrictions =

    permit_mynetworks,

    permit_sasl_authenticated,

    reject_invalid_helo_hostname,

    reject_non_fqdn_helo_hostname,

    reject_unauth_pipelining

 

smtpd_sender_restrictions =

    permit_mynetworks,

    permit_sasl_authenticated,

    reject_non_fqdn_sender,

    reject_unknown_sender_domain,

    reject_unauth_pipelining

 

smtpd_relay_restrictions =

    permit_mynetworks,

    permit_sasl_authenticated,

    ###

    # VITAL, empêche l'open relay

    reject_unauth_destination

    ###

 

smtpd_recipient_restrictions =

    permit_mynetworks,

    permit_sasl_authenticated,

    reject_non_fqdn_recipient,

    reject_unknown_recipient_domain,

    reject_unauth_pipelining

 

smtpd_data_restrictions =

    permit_mynetworks,

    permit_sasl_authenticated,

    reject_multi_recipient_bounce,

    reject_unauth_pipelining

 

virtual_transport = lmtp:unix:private/dovecot-lmtp

virtual_mailbox_domains = ldap:/etc/postfix/ldap/virtual_domains.cf

virtual_mailbox_maps = ldap:/etc/postfix/ldap/virtual_mailbox.cf

virtual_alias_maps = ldap:/etc/postfix/ldap/virtual_alias.cf

 

Quelques explications :

append_dot_mydomain = yes

ajoute le domaine au mail locaux qui sont envoyés (si un mail local est envoyé depuis un service sur le serveur, genre cron, etc… il sera de la forme root@mail.domaine1.fr au lieu de root@mail).

Centralisant tous mes mails, éventuellement d’autres serveur, c’est une info dont j’ai besoin (on peut aussi réécrire l’expéditeur, etc..).

notify_classes = bounce, delay, policy, protocol, resource, software

Définit les messages d’erreurs que recoit le postmaster. A affiner selon ce que vous voulez. Voir la doc de Postfix pour plus de détails.

myhostname = mail.domaine1.fr

mydestination = $myhostname, mail, localhost.localdomain, localhost

Le nom de votre serveur de mail. Peut être différent, mais dans mon cas, vu ma config Dns, de l’extérieur ou de l’interieur, ca reste le meme nom.
Ensuite, les destinations qu’il accepte. On ne liste ici aucun domaine qu’on gère, ceux ci sont déclarés dans les alias virtuels.

Pour la partie SSL/TLS/SALS on remarque deux groupes d’options : smtp_* et smtpd_*

Smtp concerne la patie client de postfix, c’est à dire celle qui envoie les mails aux autres serveurs SMTP (aussi appelés MX).
Smtpd concerne la partie serveur, celle qui recoit les mails, soit des clients, soit des autres MX.

smtp_tls_security_level = may

indique que le client SMTP de postfix,  quand il se connecte à un autre MX, supporte le TLS.

smtpd_tls_security_level = may

indique que le serveur SMTP de Postfix, quand il reçoit une connexion d’un client (mx ou soumis), supporte le TLS.

On le laisse à may pour indiquer que c’est possible sans être obligatoire. On le surchargera dans le fichier master.cf

Ne pas confondre aussi _sasl_ et _tls_ ! _sasl_ concerne l’authentification de nos utilisateusr (via Dovecot) et _tls_ le chiffrement des communications.

smtpd_tls_auth_only = yes

indique que si l’authentification est utilisé, on doit forcement être en SSL (ou TLS, ca revient au meme.)

Pour le reste, c’est du classique.

J’ai hésité à commenter toutes les restrictions… mais la doc de Postfix à ce sujet vous aidera à ma place.
Ce sont de bonnes restrictions pour commencer: elles permettent déjà de rejeter quelques tentative de spams.

Dans la partie IV du tuto, nous verrons plus en détails comment améliorer cela.

Un point important à connaitre : les permit ou reject sont testés dans l’ordre et dès que l’un match, cela stop pour la restriction en cours. L’ordre à donc une importance.

Grosso modo, pour chaque restriction, à chaque fois, j’autorise mon réseau local, mes utilisateurs authentifiés (mails soumis) et rejete les trucs mal fagotés…

 

On va ensuite modifier le fichier /etc/postfix/master.cf au début  :

submission    inet    n    -    y    -    -    smtpd

  -o smtpd_tls_security_level=encrypt

On active submission, et on surchage (-o le parametre smtpd_tls_security_level à encrypt pour forcer le tls.

Un peu plus bas, on va activer le smtps :

smtps    inet    n    -    y    -    -    smtpd

  -o smtpd_tls_security_level=encrypt

  -o smtpd_tls_wrappermode=yes

Le reste ne change pas.

Pourquoi Postfix utilise deux fichiers de configuration ?

Le fichier main.cf définit les options générales de Postfix. Le fichier master.cf, lui sert à gérer les sous process de Postfix et permet de modifier certains paramètres du fichier main.cf en les surchargeant (option -o).

B – Le Ldap

On va créer nos fichiers chargé de faire la liaison avec le serveur ldap et les ranger :

# mkdir /etc/postfix/ldap

# cd /etc/postfix/ldap

Fichier virtual_domains.cf :

server_host = ldap://ip.ldap

version = 3

bind = yes

bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr

bind_pw = passview

search_base = ou=mail,dc=debugo,dc=fr

scope = sub

query_filter = (&(maildomain=%s)(objectClass=maildomaindebugo)(maildomainactif=YES))

result_attribute = maildomain

Fichier virtual_mailbox.cf :

server_host = ldap://ip.ldap

version = 3

bind = yes

bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr

bind_pw = passview

search_base = ou=people,dc=debugo,dc=fr

scope = sub

query_filter = (&(mail=%s)(objectClass=mailaccountdebugo)(mailaccountactif=YES))

result_attribute = mail

Et le fichier virtual_alias.cf :

server_host = ldap://ip.ldap

version = 3

bind = yes

bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr

bind_pw = passview

search_base = ou=mail,dc=debugo,dc=fr

scope = sub

query_filter = (&(mailaliasfrom=%s)(objectClass=mailaliasdebugo)(mailaliasactif=YES))

result_attribute = mailaliasto

Pour des explications sur les filtres, vous en aurez dans la partie suivante, consacrée à Dovecot.

On sécurise :

# chmod 640 /etc/postfix/ldap/

# chown :postfix /etc/postfix/ldap/*

Puis on recharge Postfix :

# postfix reload

Et on peut tester les liens avec le ldap :

# postmap -q domaine1.fr ldap:/etc/postfix/ldap/virtual_domains.cf

nous retourne le domaine s’il existe.

# postmap -q postmaster@domaine1.fr ldap:/etc/postfix/ldap/virtual_alias.cf

donne le compte vers le lequel est envoyé l’alias.

# postmap -q toto@domaine1.fr ldap:/etc/postfix/ldap/virtual_mailbox.cf

nous retourne le mail s’il existe.

C – Alias locaux

Il reste un dernier petit point, les alias locaux de la machine.

Comme je l’ai dis avant, je veux qu’à terme, ce serveur mail gère également les mails de mes autres vm pour tout centraliser.

Et je veux tout rapatrier sur mon adresse mail toto@domaine1.fr.

On édite le fichier /etc/aliases pour y mettre :

postmaster: postmaster@domaine1.fr

root: toto@domaine1.fr

Pour mémoire, postmaster@domaine1.fr est défini comme un alias de toto@domaine1.fr dans le ldap.

On exécute la commande :

# newaliases

pour convertir cela en fichier un fichier compréhensible de postfix et on le recharge :

# postfix reload

 

IV – Conclusion

Postfix est opérationnel. Vous voyez, ce n’est pas si terrible ! On ne fait qu’effleurer la configuration, la documentation de Postfix est très complète et on peut configurer plein de scénarios…

Maintenant pour le tester, comme nous n’avons pas encore Dovecot derriere, on va se contenter de juste tester la communication d’un MX vers le nôtre :

Le site https://www.checktls.com/TestReceiver permet de faire cette vérification, et l’on voit de suite si le TLS est bon. On peut aussi classiquement en telnet, mais c’est… long…

Le site https://mxtoolbox.com/ est très pratique également.

Ha oui, au passage, le fichier clé pour debug, c’est bien évidement le fidèle :

/var/log/mail.log

 

Voila qui termine pour le moment le sujet Postfix. Dans la partir suivant, nous allons mettre en place Dovecot.

Dovecot

I – La base

A – Utilisateur Vmail

Nous allons créer l’utilisateur virtuel vmail ainsi que le répertoire qui stockera les mails :

# groupadd -g 11111 vmail

# useradd -g vmail -u 11111 vmail -d /home/vmail -m

# chown vmail: /home/vmail -R

# chmod 770 /home/vmail

Bien sur, dans l’idéal, ce stockage est redondant, etc… La, on simplifie, le reste est déjà conséquent…

 

B – Du ménage

Concernant la configuration de Dovecot, celui ci à la mauvaise idée de tout éclater dans une foultitude de fichiers.
Avant tout, faisons donc du tri…

# cd /etc/dovecot/conf.d

# rm 10-director 10-tcpwrapper 90-acl auth-*

et dans le répertoire /etc/dovecot :

# cd /etc/dovecot

# rm dovecot-dict-* dovecot-sql.conf.ext dovecot-ldap.conf.ext

C – De la config

On passe maintenant à la configuration. On va éditer le fichier /etc/dovecot/dovecot.conf et tout remplacer par :

protocols = imap lmtp

 

!include conf.d/*.conf

Oui, c’est concis, le reste sera dans le sous répertoire conf.d :

# cd /etc/dovecot/conf.d

Et la pour chaque fichier, remplacez tout son contenu par ce que je vous donne.

 

1 – Fichier 10-auth.conf

auth_cache_size = 0

auth_cache_ttl = 1 hour

auth_cache_negative_ttl = 1 hour

auth_mechanisms = plain

passdb {

  driver = ldap

  args = /etc/dovecot/dovecot-ldap-pass.conf.ext

}

userdb {

  driver = prefetch

}

userdb {

  driver = ldap

  args = /etc/dovecot/dovecot-ldap-user.conf.ext

}

Dans ce fichier, on déclare la façon dont Dovecot récupère les infos. On reviendra plus en détail dessus après…

 

2 – Fichier 10-logging.conf

#log_path = syslog

#debug_log_path =

#syslog_facility = mail

#auth_verbose = no

#auth_verbose_passwords = no

#auth_debug = no

#auth_debug_passwords = no

#mail_debug = no

#verbose_ssl = no

 

plugin {

  #mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename

  # Available fields: uid, box, msgid, from, subject, size, vsize, flags

  # size and vsize are available only for expunge and copy events.

  #mail_log_fields = uid box msgid size

}

 

#log_timestamp = "%b %d %H:%M:%S "

#login_log_format_elements = user=<%u> method=%m rip=%r lip=%l mpid=%e %c

#login_log_format = %$: %s

#mail_log_prefix = "%s(%u): "

 

# %$ - Delivery status message (e.g. "saved to INBOX")

# %m - Message-ID

# %s - Subject

# %f - From address

# %p - Physical size

# %w - Virtual size

#deliver_log_format = msgid=%m: %$

Ici, auth_verbose et auth_debug sont bien pratiques en cas de soucis avec les connexions au LDAP, mail_debug pour les filtres Sieves (et autres, quota, etc…).

 

3 – Fichier 10-mail.conf

mail_home = /home/vmail/%d/%n

mail_location = maildir:~/mailbox

 

namespace inbox {

  separator = /

  inbox = yes

}

 

mail_uid = 11111

mail_gid = 11111

mail_privileged_group = vmail

first_valid_uid = 11111

last_valid_uid = 11111

first_valid_gid = 11111

last_valid_gid = 11111

 

mail_plugins = $mail_plugins

Emplacement des mails que je range en fonction du domaine et du nom. Ensuite,uig/gid de vmail… Rien de sorcier.

 

4 – Fichier 10-master.conf

mail_fsync = never

 

service imap-login {

  inet_listener imap {

    port = 143

  }

}

 

service imap {

  service_count = 64

  process_min_avail = 1

}

 

service lmtp {

  unix_listener /var/spool/postfix/private/dovecot-lmtp {

    group = postfix

    mode = 0600

    user = postfix

  }

}

 

service auth {

  unix_listener /var/spool/postfix/private/auth {

    mode = 0660

    user = postfix

    group = postfix

  }

}

 

service auth-worker {

  user = vmail

}

Dans ce fichier, on déclare nos services : imap-login, imap, lmtp (utilisé pour le transfert de mails entre Postfix et Dovecot) et le service auth, qui service à Postfix pour authentifier les utilisateurs en SMTPS.

 

5 – Fichier 10-ssl.conf

ssl = required

ssl_ca = </etc/ssl/private/domaine1.fr/ca.pem

ssl_cert = </etc/ssl/private/domaine1.fr/cert.pem

ssl_key = </etc/ssl/private/domaine1.fr/key.pem

ssl_dh_parameters_length = 2048

ssl_protocols = !SSLv3 !TLSv1 !TLSv1.1 TLSv1.2

ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL

ssl_prefer_server_ciphers = yes

Le SSL, classique…

6 – Fichier 15-mailboxes.conf

namespace inbox {

  separator = /

  mailbox Drafts {

    auto = subscribe

    special_use = \Drafts

  }

  mailbox Junk {

    auto = subscribe

    special_use = \Junk

  }

  mailbox Trash {

    auto = subscribe

    special_use = \Trash

  }

  mailbox Sent {

    auto = subscribe

    special_use = \Sent

  }

  mailbox Archive {

    auto = subscribe

    special_use = \Archive

  }

}

La, on définit l’architecture de base de nos boites aux lettres. Création des répertoires spéciaux et auto souscription pour que l’utilisateur les voit de suite.

 

7 – Fichier 20-imap.conf

imap_idle_notify_interval = 30 mins

 

protocol imap {

  mail_max_userip_connections = 50

  mail_plugins = $mail_plugins imap_sieve

  postmaster_address = postmaster@domaine1.fr

}

Configuration du protocole IMAP.

 

8 – Fichier 20-lmtp.conf

protocol lmtp {

  mail_fsync = optimized

  mail_plugins = $mail_plugins sieve

  postmaster_address = postmaster@domaine1.fr

}

Configuration du protocole LMTP.

 

9 – Fichier 20-managesieve.conf

protocols = $protocols sieve

 

service managesieve-login {

  inet_listener sieve {

    port = 4190

  }

  service_count = 1

  #process_min_avail = 0

  #vsz_limit = 64M

}

Configuration de ManageSieve.

10 – Fichier 90-sieve.conf

plugin {

  sieve = file:~/sieve;active=~/.dovecot.sieve

  sieve_before = /etc/dovecot/sieve-global

 

  recipient_delimiter = +

  sieve_quota_max_storage = 50M

}

Configuration de Sieve.

Pfff, c’était long hein ? Et bien, on a pas fini…

 

II – Fichiers de mapping Ldap

A – Selon la Doc de Dovecot

Avant de faire nos fichiers pour le Ldap, on va regarder à quoi devrait ressembler un dovecot-ldap.conf.ext qu’on peut rencontrer sur le grand internet, un exemple souvent cité (bon, les filtres sont les miens, mais c’est l’idée) :

uris = ldap://ip.interne

dn = cn=viewer,ou=system,dc=debugo,dc=fr

dnpass = passview

debug_level = 0

auth_bind = no

ldap_version = 3

base = ou=people,dc=debugo,dc=fr

scope = subtree

 

user_attrs = mailaccountquota=quota_rule=*:bytes=%$

user_filter = (&(uid=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))

 

pass_attrs = mail=user,userPassword=password

pass_filter = (&(uid=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))

C’est la que le auth_debug et mail_debug sont utiles … Mais un peu de théorie avant.

 

B – Passdb et Userdb

Dovecot utilise deux bases : passdb et userdb, déclarées dans cond.f/10-auth.conf ou j’utilise une petite astuce, le prefetch, pour éviter les doubles requêtes…

Il faut aussi savoir que Dovecot utilise des variables. Celles qui nous intéressent sont :

Ici, nous n’utiliserons que %u.

Au niveau du résultat ldap, l’ordre est :

attribut_ldap:attribut_dovecot

Et donc :

pass_attrs = mail=user,userPassword=password

indique que le champ mail de mon ldap correspond à l’utilisateur, du coup j’ai la bonne association.

 

C – Bind Ldap

Ensuite, au niveau du bind avec Ldap (la connexion avec Ldap), celui ci peut se faire de deux façons.

1 – auth_bind = yes

Cela permet de faire en sorte que le test du mot de passe se fasse directement avec le compte de l’utilisateur. Dovecot dans ce cas n’a pas besoin de lire le pass avec le compte viewer.

En contre partie, c’est plus lent, Dovecot attendant que la connexion avec le Ldap soit terminée avant de passer à la suivante.

2 – auth_bind = no

La, il y a besoin que le compte viewer puisse lire le mot de passe (d’où les acls mises en place dans la partie LDAP). Ayant de toute façon besoin de ce compte pour d’autres applications, ça ne me dérange pas.

De plus, c’est asynchrone, Dovecot peut lancer plusieurs requêtes concomitantes sans attendre apres.

Bref, on part sur le second choix.

 

D – Paf

Cependant, cette config me pose encore un problème… Lorsque l’on se connecte en IMAP on se présente donc avec un simple toto par contre, lors du LMTP, le %u présenté par Postfix est le mail complet, toto@domaine1.fr et la, bah ça foire au niveau du filtre ldap, qui est pour mémoire :

(&(uid=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))

Que faire ? Refaire nos utilisateurs pour que leur uid soit leur mail ? Heu, c’est pas l’idée à la base…

Donc, pour ça, j’avais trouvé une première solution :

user_filter = (&(|(mail=%u)(uid=%u))(objectClass=mailaccountdebugo)(mailaccountactif=YES))

Ha, les filtres LDAP et leur notation préfixée. Si vous avez eu une calculette Sharp dans les 90’s, vous devez connaître (et être vieux 😉 ). Bon, elles utilisaient la notaion polonaise inverse où l’opérateur est à la fin, mais c’est la même idée… Si vous avez fait de l’algèbre booléenne ou bien joué avec les AND, OR, XOR, et NAND (du genre, comment faire un OR avec que des NAND, tables de vérités, etc..), et bien le + (ou) est remplacé par | et le . (et) par &.

On peut résumer :

(&(Bloc1)(Bloc2)(Bloc3)) -> On veut Bloc1 ET Bloc2 ET Bloc3

Bloc1=(|(A)(B)) -> A OU B

C’est beau hein ! Bah c’est balo car on en va pas l’utiliser. En effet, cela amène un effet de bord :  je peux désormais me connecter à ma bal avec comme login mon mail….
Après,  on aime ou  on n’aime pas. Perso, je ne préfère pas laisser cette possibilité, pour éviter les vilains qui tenteraient de se connecter en connaissant déjà le login…

Apres tout, j’aurais pu en rester la et me dire tant pis, mais au final c’était ne pas vraiment comprendre Dovecot…

 

E – Solution

Il faut faire en sorte que les appels userdb et passdb soient distincts…

Pour la configuration, on aura donc deux fichiers :

/etc/dovecot/doveto-ldap-pass.conf.ext :

uris = ldap://ip.ldap

dn = cn=viewer,ou=system,dc=domaine1,dc=fr

dnpass = passview

debug_level = 0

auth_bind = no

ldap_version = 3

base = ou=people,dc=domaine1,dc=fr

scope = subtree

 

pass_attrs = mail=user,userPassword=password,mailaccountquota=userdb_quota_rule=*:bytes=%$

pass_filter = (&(uid=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))

La, on demande aussi au passage un attribut quota avec userdb userdb_quota_rule=*:bytes=%$ et qui sera utilisé dans le prefetch pour éviter de refaire une requête LDAP.

Et le fichier /etc/dovecot/dovecot-ldap-user.conf.ext :

uris = ldap://ip.ldap

dn = cn=viewer,ou=system,dc=domaine1,dc=fr

dnpass = passview

debug_level = 0

auth_bind = no

ldap_version = 3

base = ou=people,dc=domaine1,dc=fr

scope = subtree

 

user_attrs = mailaccountquota=quota_rule=*:bytes=%$

user_filter = (&(mail=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))

La, on filtre sur le champ mail pour retrouver le compte correspondant.

On sécurise :

# chmod 600 /etc/dovecot/dovecot-ldap*

On va recharger Dovecot et regarder les logs voir si tout démarre bien :

# servive dovecot restart

# tail /var/log/mail.log -n 100

 

III – Sieve

1 – La base

Dovecot permet donc de filtrer les messages en utilisant le protocole Sieve. Il les range à leur arrivée selon les règles, global et utilisateur.
Pour le global, on aura besoin que d’une seule règle : les messages marqués comme Spam sont dirigés dans le répertoire Spam.
Par la suite, chaque utilisateur pourra ajouter ses règles afin de filtrer comme il l’entend.

On a déjà activé Sieve au préalable. Il ne reste plus qu’à faire quelques opérations.

Pour le global :

mkdir /etc/dovecot/sieve-global

chown vmail /etc/dovecot/sieve-global

Nous rangerons nos scripts globaux dans ce répertoire, qui s’exécutera avant les filtres utilisateurs.

Si vous voulez faire les vérifications global apres, dans le fichier 90-sieve.conf, il faudra indiquer :

sieve_after = /etc/dovecot/sieve-global

Et on peut bien sûr combiner.

 

Créez ensuite le fichier /etc/dovecot/sieve-global/global.sieve avec le contenu qui suit :

require ["variables", "envelope", "fileinto", "mailbox", "regex", "subaddress", "body"];

 

if header :contains "X-Spam" "Yes" {

  fileinto "Junk";

  stop;

}

Tout bête, si le header contient X-spam à Yes, on le déplace dans les indésirables ( Le X-spam sera rajouté par Rspamd).

Le stop indique d’arrêter le traitement. En effet, si d’autres filtres (users ou globaux) matchent également, le message sera dupliqué.

Puis  on change l’user et les droits :

#chown vmail: /etc/dovecot/sieve-global/global.sieve

#chmod 750 /etc/dovecot/sieve-global/global.sieve

On peut le compiler :

# sievec /etc/dovecot/sieve-global/global.sieve

qui donnera un fichier /etc/dovecot/sieve-global/global.svbin, version compilée de nos règles.

Cette opération est cependant facultative et elle sera de toute façon exécutée par Dovecot à la première occasion si vous le n’avez pas fait.

Si on le fait, on pense  à modifier les droits :

# chown vmail /etc/dovecot/sieve-globa/global.svbin

Je serais même tenté de dire que la première fois, c’est mieux de laisser Dovecot le faire, en regardant les logs et avec l’option mail_debug = yes on voit très rapidement où se trouve le problème s’il y en a un (et généralement, ça chouine pour des histoires de permissions). Pour les filtres utilisateurs, c’est la même tambouille, Dovecot les compilant au moment ou il les charge, s’il n’existent pas ou sont obsolètes.

 

2 – Niveau Utilisateur

Pour modifier les filtres d’un utilisateur, on peut utiliser un webmail préalablement configuré. Pour le moment, je ne couvre pas cette partie (ce sera pour plus tard), donc pour le moment, on va plutôt passer par un client tel que Thunderbird.

Par défaut, Thunderbird ne les gère pas, mais il suffit de rajouter ce module complémentaire.
Ensuite menu Outils/Paramètres Sieve et activez la gestion de Sieve. Les paramètres sont identiques à l’IMAP, mais sur le port 4190.

Et ensuite dans le menu Outils/Filtres Sieve (M). Faites nouveau pour créer un nouveau fichier de règles.

Voila un exemple de règles :

require ["variables", "envelope", "fileinto", "mailbox", "regex", "subaddress", "body"];

if header :contains "subject" "Postfix SMTP server" {

    fileinto "Serveur";

}

En cas de fautes, le plugin vous le signale. Il ne reste qu’a enregistrer. A noter : Sieve permet d’avoir plusieurs fichiers de filtrage, mais un seul peut être actif à la fois.

Bien sur, Sieve permet de faire beaucoup de choses, avec gestion de conditions, variables, etc… Ce sera l’occasion de faire un article complet (ou presque) sur Sieve un peu plus tard.

 

3 – Tests

Comme je l’ai dis, l’option mail_debug = yes permet de voir de suite dans le fichier de log /var/log/mail.log c e qui ne va pas.

 

 

IV – Quota

A – Configuration

Pour rajouter la gestion du quota, il suffit de quelques manipulations. Pour rappel, si le champ dans le ldap est égal à zéro, cela veut dire pas de quota. Notez également que le champ est exprimé en bytes.

Dans le fichier /etc/dovecot/conf.d/10-mail.conf on va modifier :

[...]

mail_plugins = $mail_plugins quota

[...]

Dans le fichier /etc/dovecot/conf.d/20-imap.conf :

[...]

mail_plugins = $mail_plugins imap_sieve imap_quota

[...]

Puis dans le fichier 20-lmtp.conf :

[...]

mail_plugins = $mail_plugins sieve quota

[...]

Et pour terminer on remplace le contenu du fichier /etc/dovecot/conf.d/90-quota.conf par ce qui suit :

plugin {

  quota = maildir:User quota

  quota_warning = storage=90%% quota-warning 90 %u

}

 

service quota-warning {

  executable = script /etc/dovecot/quota.sh

  user = vmail

  unix_listener quota-warning {

    user = vmail

  }

}

Voila, c’est en place.

B – Avertissement automatique

On va rajouter le petit script qui va envoyer le mail d’alerte.

Dans un fichier /etc/dovecot/quota.sh mettez cela :

#!/usr/bin/env bash

 

PERCENT=${1}

USER=${2}

 

cat << EOF | /usr/lib/dovecot/dovecot-lda -d $USER -o "plugin/quota=maildir:User quota:noenforcing"

From: no-reply@domaine1.fr

Subject: HOHOHO: Votre BAL est pleine a ${PERCENT}

Content-Type: text/plain; charset="utf-8"

 

HOHOHO

Votre BAL est pleine a ${PERCENT}. Faut faire du menage mon coco !

EOF

Rien de bien compliqué.

On s’occupe des permissions :

# chmod +x /etc/dovecot/quota.sh

# chown vmail /etc/dovecot/quota.sh

L’œil attentif remarquera que l’on fait appel à dovecot-lda pour ce mail. J’ai tenté avec le lmtp, où pourtant -d a la même utilité, mais je me mange une erreur. Tant pis, au final, lda est toujours dispo, et n’est invoqué qu’au besoin. Autant dire que ça ne va pas beaucoup tourner

On édite le fichier /etc/dovecot/conf.d/15-lda.conf pour tout remplacer par :

protocol lda {

  info_log_path =

  log_path =

  mail_plugins = sieve quota

  postmaster_address = postmaster@domaine1.fr

  quota_full_tempfail = yes

}

On recharge Dovecot :

# dovecot reload

 

C – Tests

Si vous voulez ajouter un quota à un utilisteur pour tester, sur le ldap, un fichier mod_quota.ldif :

dn: uid=toto,ou=people,dc=debugo,dc=fr

changetype: modify

replace: mailaccountquota

mailaccountquota: 2147483648

Que vous injectez :

# ladd -f mod_quota.ldif

La, il est réglé à 2Go.

Ensuite, de retour sur le serveur mail, on va déja regarder si le quota est fonctionnel :

# doveadm quota get -u toto@domaine1.fr

doit retourner quelque chose qui ressemble à ca :

Quota name  Type     Value   Limit    %

User quota  STORAGE  125786  2097152  5

User quota  MESSAGE  2329    -

On va aussi tester le script :

./quota.sh 90 toto@domaine1.fr

Et pour tester en conditions réelles, attention, il faut savoir que le mail n’est envoyé qu’une seule fois, au moment où le quota est dépassé.

Par exemple, si vous activez le quota avec une bal deja hors quota vous n’aurez jamais le mail. Du coup, pour tester, c’est pas évident… faut jouer avec une toute petite bal. Mais si les deux commandes au préalable fonctionnent sans problemes, ca doit marcher en production.

Pour voir le quota avec Thunderbird, je conseille Display Quota.

 

V – Conclusion

Voila pour cette troisième partie où nous avons fait connaissance avec Dovecot. Je pourrais vous parler en profondeur de la commande doveadm qui permet de faire pas mal de choses mais ce sera pour un tuto annexe… En attendant, rien ne vous empêche de vous documenter.

Vous voulez la bonne nouvelle ? Notre serveur de messagerie est opérationnel.

Pour tester, rien de tel qu’un client lourd. Thunderbird pour Windows, Evolution ou autres pour Linux.

 

Vous devez pouvoir recevoir et envoyer des mails.

Attention cependant, aucune protection contre le spam n’est encore en place à ce niveau. De la meme façon,  vos mails envoyés vers certains domaines (gmail, hotmail) risquent fort de se retrouver classés comme spams (DKIM, SPF et DMARC pas encore en place).

Et oui, j’ai dis opérationnel, pas terminé ! Mais ne ne perdez pas espoir, on a fait le plus dur.

Maintenant, dans la partie IV, nous allons optimiser un peu Postfix.

Optimisation de Postfix

I – Sécurisation SMTPS et Submission

La partie II, consacrée à Postfix laisse dans notre configuration une potentielle future faille.

Vous le savez, un SMTP externe communiquera avec le votre via le port 25, mais imaginons qu’un instant, un serveur se connecte à vos ports 465 ou bien 587…
Et bien, il ne sera pas embêté. Au final, pour le moment, ce n’est pas bien méchant car il suivra les restrictions qu’il aurait rencontré via le port 25, mais si nous mettons en place des restrictions différentes selon les services (et c’est ce que nous ferons plus tard), et bien, on risque d’avoir des surprises.

Autant y remédier de suite en bloquant la possibilité à un serveur SMTP de se connecter la ou il ne doit pas.

On édite le fichier /etc/postfix/master.cf :

[...]

submission inet   n   -   y   -   -   smtpd

  -o smtpd_tls_security_level=encrypt

  -o smtpd_client_restrictions=permit_sasl_authenticated,reject

smtps      inet   n   -   y   -   -   smtpd

  -o smtpd_tls_security_level=encrypt

  -o smtpd_tls_wrappermode=yes

  -o smtpd_client_restrictions=permit_sasl_authenticated,reject

[...]

Pour ces deux services, la directive smtpd_client_restriction du main.cf est remplacée : on permet les utilisateurs connectés et on rejette le reste.

 

II – Antiforge

A – Explication

Derrière ce terme, se cache quelque de tout simple : le fait de pouvoir modifier (forger) sans vergogne l’adresse de l’expéditeur. Je m’explique :

On va donc rajouter une restriction au moment de la vérification du sender afin de limiter tout cela.

On édite le fichier /etc/postfix/main.cf et on ajoute dans la directive smtpd_sender_resctriction :

smtpd_sender_restrictions =

  reject_sender_login_mismatch,

  permit_mynetworks,

  [...]

Cette nouvelle directive s’appuie sur une sender_login_maps, qu’on va déclarer plus bas :

smtpd_sender_login_maps = ldap:/etc/postfix/ldap/virtual_senders.cf

On va créer le fichier qui va faire le lien avec le ldap : /etc/postfix/ldap/virtual_senders.cf :

server_host = ldap://ip.ldap

version = 3

bind = yes

bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr

bind_pw = passview

search_base = dc=debugo,dc=fr

scope = sub

query_filter = (|(&(mailaliasfrom=%s)(objectClass=mailaliasdebugo)(mailaliasactif=YES))(&(mail=%s)(objectClass=mailaccountdebugo)(mailaccountactif=YES)))

result_attribute = mail mailaliasto

Simple, cela retourne le propriétaire de la boite demandée si il y en a un.

Ensuite, deux cas de figures :

Vite fait, je reviens bien sur la distinction TLS et SASL :

A ne pas confondre avec TLS (ou SSL) qui est la sécurité appliquée à la connexion.

On recharge Postfix :

# postfix reload

B – Pour le fun

Imaginons que dans notre schéma LDAP, nous ayons un attribut mailaliassend qui stipule si un alias a le droit ou non d’envoyer des mails. Après tout, pourquoi pas…

Notre fichier /etc/postfix/ldap/virtual_senders.cf pourrait ressembler à cela :

server_host = ldap://ip.ldap

version = 3

bind = yes

bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr

bind_pw = passview

search_base = dc=debugo,dc=fr

scope = sub

query_filter = (|(&(mailaliasfrom=%s)(objectClass=mailaliasdebugo)(mailaliasactif=YES)(mailaliassend=YES))(&(mail=%s)(objectClass=mailaccountdebugo)(mailaccountactif=YES)))

result_attribute = mail mailaliasto

La puissance du LDAP, tout simplement…

 

III – Contrôle d’accès

Dans sa grande générosité au niveau de ses possibilités, Postfix permet également d’effectuer des vérifications d’accès à l’aide de quatre contrôles :

Dans le cadre du renforcement de notre serveur Postfix, seul check_sender_access sera vraiment obligatoire, les autres, c’est au cas pas cas.

Ces vérification s’appuient sur des données formatées de la sorte :

111.111.111.111 REJECT

// ou bien

toto@domaine1.fr OK

Bien que le OK soit implicite (si pas d’entrée, c’est OK par défaut), il peut être nécessaire dans certains cas de l’expliciter.

Au niveau des actions possible, nous trouvons entre autres :

Plus de détails ici : http://www.postfix.org/access.5.html

Si vous utilisez des fichiers statiques, après chaque modification, il faudra invoquer :

# postmap /etc/postfix/nomdufichier

Et pour rappel, vu notre configuration actuelle, ces quatre contrôles se font dans un sens (mail entrant) et dans l’autre (mail sortant).

Chacun de ces contrôles prendra place ensuite dans son bloc smtpd_*_restrictions correspondant.

 

A – check_client_access

Ici, on peut autoriser ou interdire des IPs ou des domaines spécifiques.

Exemple :

111.222.111.222 REJECT

domaineabloquer.com REJECT

Et cela se place de la sorte :

smtpd_client_restrictions =

    check_client_access hash:/etc/postfix/acces_client,

    [...]

Pour filtrer des lourds (spammeurs, bots, etc…), ce n’est pas forcement la meilleure solution. D’une, il faut que la la liste d’accès soit maintenue à jour, et c’est alors un travail quotidien, ou presque…

Seconde « limitation », même en cas de Reject, la session SMTP ira jusqu’au RCPT ou bien sur, elle sera terminée, mais on a gaspillé de la ressource à aller si loin.

On peut demander à Postfix d’arrêter la communication dès qu’une restriction s’applique (en mettant l’option  smtpd_delay_reject = no) mais pour trouver un éventuel soucis par la suite, ce peut être gênant. Autre problématique, certains clients gèrent mal une connexion coupée de la sorte…

Je conseille donc de laisser comme c’est par défaut.

Et donc pour bloquer des IPS spécifiques, je passe soit par mon firewall, soit par Postscreen (qu’on verra plus tard).

 

B – check_helo_access

Ici est effectué un contrôle sur le helo. Comme pour le client, c’est vite compliqué de maintenir quelque chose à jour.

Cependant, on peut quand même effectuer un petit contrôle de routine pour éviter le helo qui serait le notre, ça ne mange pas de pain…

smtpd_helo_restrictions =

    permit_mynetworks,

    permit_sasl_authenticated,

    check_helo_access ldap:/etc/postfix/ldap/check_helo_domains_reject.cf,

    [...]

Et le fichier /etc/postfix/ldap/check_helo_domains_reject.cf correspondant :

server_host = ldap://ip.ldap

version = 3

bind = yes

bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr

bind_pw = passview

search_base = ou=mail,dc=debugo,dc=fr

scope = sub

 

query_filter = (&(maildomain=%s)(objectClass=maildomaindebugo)(maildomainactif=YES))

result_attribute = maildomain

result_filter = REJECT Menteur

Rien de sorcier…

On pense à recharger Postfix :

# postfix reload

C – check_recipient_access

La, on peut contrôler le destinataire :

Par exemple :

toto@domaine.fr REJECT

Pour bloquer les mails destiné a mon utilisateur toto. Oui, c’est pas franchement utile…

Ou bien encore :

adresseextene@gmail.com REJECT

Pour bloquer les mails à destination de cette adresse. L’intérêt la aussi, dans notre cas de figure, est faible, mais ça existe et ça peut servir.

 

D – check_sender_access

Ici, on va effectuer un contrôle au niveau de l’expéditeur et on va revenir  sur l’antiforge dont je parlais avant pour s’intéresser à un cas que je n’ai pas traité :

Imaginons un serveur SMTP qui nous envoie un mail avec comme FROM TO un mail du genre userbidon@domaine1.fr, la bal n’appartenant à personne, le reject_sender_login_mismatch qu’on a vu plus haut ne bloquera rien,  le mail passera.

On va donc y remédier. L’idée étant d’autoriser en FROM TO nos mails qui existent et de rejeter le reste.

Dans le bloc smtpd_sender_resctrictions, nos usagers sont déjà autorisés via permit_sasl_authenticated, on va donc ajouter juste après la restriction pour nos domaines.

On aurait alors besoin d’un fichier ressemblant à ça :

@domaine1.fr      REJECT

@domaine2.fr    REJECT

Et comme on a le Ldap pour alimenter cela, on va donc passer  par un fichier nommé /etc/postfix/ldap/check_sender_domains_reject.cf :

server_host = ldap://ip.ldap

version = 3

bind = yes

bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr

bind_pw = passview

search_base = ou=mail,dc=debugo,dc=fr

scope = sub

 

query_filter = (&(maildomain=%s)(objectClass=maildomaindebugo)(maildomainactif=YES))

result_attribute = maildomain

result_filter = REJECT Ho le vilain....

Et cela se place de la sorte  dans le fichier /etc/postfix/main.cf :

smtpd_sender_restrictions =

    reject_sender_login_mismatch,

    permit_mynetworks,

    permit_sasl_authenticated,

    check_sender_access ldap://etc/postfix/ldap/check_sender_domains_reject.cf,

    [...]

L’ordre est important. Si le check_sender_access est positionné avant le permit_sasl_authenticated, nos propres utilisateurs ne pourraient pas envoyer de mails.

On recharge :

# postfix reload

Et voila l’antiforge amélioré.

 

IV – Les « Header Checks »

Dernière série de contrôle que l’on peut effectuer ou l’on va regarder un peu plus profondément dans le mail.

Postfix nous propose plusieurs types de contrôles sur les headers :

Plus de détails ici : http://www.postfix.org/header_checks.5.html

Pour les utiliser, il faut tout d’abord installer le module pcre de Postfix :

# apt-get install postfix-pcre

On recharge Postfix :

# postfix reload

A partir de maintenant, on va pouvoir inspecter, via des REGEX, ce qu’il y a dans les mails.

La syntaxe est la suivante :

/^Subject:.*viagra*/ REJECT Pas besoin, merci

/^From: *toto*/    REJECT On connait la blague

De mon avis et expérience, pour filtrer le spam, ce n’est plus vraiment la meilleure solution sauf cas particulier. Compliqué de maintenir un truc à jour, risque d’un regex un peu foireux qui pourrait être trop restrictif…

Pour information, il est possible de tester vos regex de la sorte :

# postmap -q "Subject: viagra" pcre:/etc/postfix/header_checks

Cela doit vous renvoyer la règle qui s’applique.

Si vous voulez tester avec un mail sauvegardé dans un fichier :

# postmap -q - pcre:/etc/postfix/header_checks < mail.txt

Le second – après le -q est important.

 

Donc pour le traitement du spam, on fait mieux, cependant, je me sers du header_check pour deux choses.

Créons  d’abord le répertoire qui va accueillir nos fichiers :

# mkdir /etc/postfix/check/

A – Filtrage des fichiers à risque

Au niveau filtrage en entrée, pour la démonstration, je ne montre qu’un exemple simple. A vous après de faire vos propres règles.

Créons un fichier /etc/postfix/check/header_checks_in avec ce qui suit :

/^s*Content­.(Disposition|Type).*names*=s*"?(.+.(bat|exe|com|scr|vbs))"?s*$/ PREPEND X-DEBUGO:WARN

Ici, un header perso X-DEBUGO: WARN est ajouté si le mail contient un fichier avec les extensions bat, exe, com, etc… Celui ci pourra me servir à effectuer un filtre avec Sieve.

Au niveau des actions, on retrouve peu ou prou ce qu’on avait pour les contrôles d’accès. On peut donc aussi utiliser REJECT pour le rejeter, REDIRECT xxx@domaine1.fr , etc…

Voila pour les contrôles en entrée.

B – Supprimer les informations sensibles

L’autre utilité est de pouvoir masquer certaines informations de vos mails sortants, tel que votre IP d’envoi, votre client mail… Par défaut, les headers ajoutés par votre client de messagerie sont un peu trop causant…

Si on regarde ces fameux headers d’un mail qui partirait de chez vous vers un destinataire externe, le premier Received ressemblerait à cela :

Received: from [monip] (monreverse[monip])

        (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))

        (No client certificate requested)

        by mail.domaine1.fr (Postfix) with ESMTPSA id 3AB4D22938

        for <destinataire@destination.com>; Mon,  21 Jul 1969 02:56:20 +0000 (UTC)

Au passage, pour lire les headers d’un mail, il faut commencer par le bas. Le premier Received que l’on voit en haut est en fait le dernier SMTP rencontré, celui du destinataire.

Et donc notre destinataire, s’il est un peu curieux, peut connaitre notre IP. Puis s’il descend un peu, il en apprendra davantage sur votre OS, etc…

Hum, ce n’est pas terrible…

Allez, nettoyons tout cela !

Dans un fichier /etc/postfix/check/header_checks_out :

/^\s*Received: from \S+ \(\S+ \[\S+\]\)(.*)/ REPLACE Received: from [127.0.0.1] (localhost [127.0.0.1])$1

/^X-Originating-IP:/ IGNORE

/^X-Mailer:/ IGNORE

/^Mime-Version:/ IGNORE

/^User-Agent:/ IGNORE

Au passage, on rencontre souvent sur internet ce regex :

/^Received:.*with ESMTPSA/ IGNORE

En lieu et place de celui que je vous ai indiqué. Celui ci est un peu trop violent à mon gout, vu qu’il supprime complétement le Received from vous concernant. Il peut toujours être utile d’indiquer que vous étiez en tls, le serveur qui a reçu le mail, etc… Je préfère donc juste masquer l’ip d’origine.

C – Oui mais…

Si on indique ces checks dans le main.cf avec :

header_checks = pcre:/etc/postfix/check/header_checks_in,pcre:/etc/postfix/check/header_checks_out

mime_header_checks = pcre:/etc/postfix/check/header_checks_in,pcre:/etc/postfix/check/header_checks_out

Ils vont se faire sur les mails qui entrent et qui sortent. Et on ne veut pas effacer les headers des mails qui nous arrivent… ni ajouter un éventuel header au mail que l’on envoie.

Que faire…

La solution élégante est de faire appel au process cleanup et d’en faire deux « sous process ». Chacun en charge d’un traitement, et affecté comme il faut.

Pour se faire, c’est assez simple :

On édite le fichier /etc/postfix/master.cf pour y ajouter pour chaque service un nouveau service cleanup :

smtp       pass   -   -   y   -   -   smtpd

  -o cleanup_service_name=subcleanin

[...]

submission inet   n   -   y   -   -   smtpd

  -o smtpd_tls_security_level=encrypt

  -o smtpd_client_restrictions=permit_sasl_authenticated,reject

  -o cleanup_service_name=subcleanout

smtps      inet   n   -   y   -   -   smtpd

  -o smtpd_tls_security_level=encrypt

  -o smtpd_tls_wrappermode=yes

  -o smtpd_client_restrictions=permit_sasl_authenticated,reject

  -o cleanup_service_name=subcleanout

 

Et plus bas, en dessous du cleanup existant, on ajoute :

cleanup     unix   n   -   y   -   0   cleanup

subcleanout unix   n   -   -   -   0   cleanup

  -o header_checks=pcre:/etc/postfix/check/header_checks_out

  -o mime_header_checks=pcre:/etc/postfix/check/header_checks_out

subcleanin  unix   n   -   -   -   0   cleanup

  -o header_checks=pcre:/etc/postfix/check/header_checks_in

  -o mime_header_checks=pcre:/etc/postfix/check/header_checks_in

Précisez bien header_checks et mime_header_checks : les headers pouvant être dans le format MIME ou ASCII, il est important de bien traiter les deux cas.

On recharge Postfix :

# postfix reload

Et voila !

V – Conclusion

Voila qui termine cette première  partie sur l’optimisation de Postfix.

J’ai ai profité pour vous montrer quelques astuces et vous initier à la toute puissance de Postfix.

Je vous invite bien évidement à consulter la doc officielle qui vous permettra de trouver réponses à vos cas particuliers. Bien sur, vous pouvez aussi poser vos questions ici même dans les commentaires.

Allez,  courage, on a bientôt terminé ! Dans la partie V, nous allons encore ajouter deux petits modules à Postfix : Policy Spf et Postscreen.

Policyd SPF et Postscreen

Nous allons ajouter Polycyd SPF et Postscreen, deux outils bien pratiques dans la lutte contre le spam.

 

I – Policyd SPF

SPF (Sender Policy Framework) est un mécanisme simple qui permet de savoir si un SMTP à l’origine d’un mail est bien légitime .

Cela s’appuie sur un enregistrement TXT dans le DNS qui ressemble à ça :

"v=spf1 ip4:ip.legitime mx -all"

Cet enregistrement stipule quel MX est autorisé à envoyer depuis le domaine.

Ici, on va mettre en place la vérification pour les mails entrants, la création dans notre DNS de notre propre SPF se fera dans la partie VII.

On commence en installant le module SPF python (il existe aussi une version perl, mais celle en python est mieux maintenue et nécessite moins de dépendances, puis le python, c’est la vie !)

# apt-get install postfix-policyd-spf-python

Il se configure dans le fichier /etc/postfix-policyd-spf-python/policyd-spf.conf ou vous indiquez ceci :

debugLevel = 1

 

HELO_reject = Fail

Mail_From_reject = Fail

 

PermError_reject = False

TempError_Defer = False

 

skip_addresses = 127.0.0.0/8,10.0.0.0/8

Les mails qui ne respectent pas les SPF seront rejetés. Par contre, s’il n’y a pas de SPF définis, on accepte (les refuser ici est une mauvaise idée, nombre de domaines légitimes n’ont pas de SPF en place…)

Ensuite, dans le fichier /etc/postfix/master.cf on va ajouter en bas :

policyd-spf unix - n n - - spawn

  user=nobody argv=/usr/bin/policyd-spf

Et dans le /etc/postfix/main.cf, on ajoute tout d’abord une ligne :

policyd-spf_time_limit = 3600s

puis en dessous, dans le bloc smtpd_sender_restrictions, on ajoute :

smtpd_sender_restrictions =

    permit_mynetworks,

    permit_sasl_authenticated,

    check_sender_access ldap://etc/postfix/ldap/check_sender_domains_reject.cf,

    check_policy_service unix:private/policyd-spf,

    [...]

On recharge :

# postfix reload

Dorénavant, chaque mail entrant subira une vérification SPF. On pourra l’observer en regardant les headers d’un mail qu’on reçoit :

Received: from mail.domaine1.fr

        by mail (Dovecot) with LMTP id N59BECWohFzNVwAAZU03Dg

        for <toto@domaine1.fr>; Mon, 21 Jul 1969 02:56:20 +0000

Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=blablabla...

Voila pour le contrôle SPF qui va permettre d’écrémer un peu plus.

 

II – Postcreen

On arrive à la chose la plus efficace pour lutter contre le spam bête et méchant. S’il ne devait en rester qu’un, ce serait lui je pense. Pourtant il ne réinvente rien et utilise des principes déjà connus, mais il le fait bien et simplement.

Il est le bouclier contre les zombies/bots, etc… que je résume en « les lourds »…

Il est… Postscreen !

A – Activation

Postscreen étant intégré dans Postfix, rien à installer, il suffit de l’activer.

Dans le fichier /etc/postfix/master.cf, commentez la ligne :

smtp  inet   n   -   y   -   -   smtpd

et décommentez juste en dessous :

smtp  inet   n   -   y   -   1   postscreen

smtpd pass   -   -   y   -   -   smtpd

dnsblog  unix   -   -   y   -   0   dnsblog

tlsproxy unix   -   -   y   -   0   tlsproxy

Le reste de la configuration se passera dans le fichier /etc/postfix/main.cf.

B – Configuration

Postcreen peut faire deux types de contrôles :

Les contrôles simples se fond avant de passer la main à Postfix. Si tout est Ok, le mail suit son chemin.

Au contraire, les contrôles profonds prennent la main sur l’ensemble du dialogue et introduisent de par ce fait, un greylisting. J’y reviens plus bas.

Pour chaque contrôle, on peut définir une action :

Un serveur qui sera accepté sera mis en liste blanche pour les prochaines fois afin de ne pas mobiliser de la ressource pour rien.

1 – Contrôles simples

Simples ne veut pas dire inefficaces. Personnellement, je n’utilise qu’eux, n’aimant pas le principe du greylisting.

a – Access list

Simplissime, ce contrôle va permettre de bloquer des IPs et contrairement au blocage dans Postfix, ici avec l’action sur drop, c’est immédiat. Ciao !

Pour l’activer, ajoutez ces lignes dans le fichier /etc/postfix/main.cf :

postscreen_access_list = permit_mynetworks, cidr:/etc/postfix/postscreen_access.cidr

postscreen_blacklist_action = drop

Le fichier /etc/postfix/postscreen_access.cidr doit ressembler à cela :

xxx.xxx.xxx.xxx reject

[...]

 

b – Greet banner

Ce contrôle joue sur une subtilité du protocole SMTP. En effet, si le serveur répond avec  « 250-On attend un pneu…« , le tiret après le 250 indique qu’il y a plusieurs lignes.

Et il attend le temps indiqué avant d’envoyer le « 250 mail.domaine1.fr ESMTP mail (Debian/GNU)« .

Du coup, un zombie trop rapide se fera avoir, et hop, dehors !

Pour l’activer, ajoutez ces lignes dans le fichier /etc/postfix/main.cf :

postscreen_greet_wait = 3s

postscreen_greet_banner = On attend un pneu...

postscreen_greet_action = drop

Le temps d’attente sert également à Postscreen pour consulter les Dnsbl qu’on voit juste en dessous.

c – Dnsbl

Ici, on va interroger des RBL.

Le principe est simple. On passe par une interrogation DNS pour savoir si un MX distant est légitime ou non.

Une réponse du genre 127.0.0.X indique qu’il ne faut pas accepter le mail (le type de réponse dépend de la liste dans la quelle se trouve l’IP). On peut éventuellement ne prendre que certaines réponses.

Pour l’activer, ajoutez ces lignes dans le fichier /etc/postfix/main.cf :

postscreen_dnsbl_sites =

 zen.spamhaus.org*2,

 bl.spamcop.net,

 b.barracudacentral.org*2

postscreen_dnsbl_threshold = 3

postscreen_dnsbl_action = drop

J’utilise trois listes. En mettre de trop n’est pas forcement une bonne idée, temps d’interrogation plus long, trouver comment bien pondérer chacune…

Sachez cependant qu’il en existe plein. Vous en trouverez ici par exemple : https://www.dnsbl.info/dnsbl-list.php

Pour faire une interrogation à la main, si votre IP est AAA.BBB.CCC.DDD :

# dig +short DDD.CCC.BBB.AAA.b.barracudacentral.org

On passe par un PTR record, ce qui fait qu’on peut connaitre « l’état » d’une IP en interrogeant n’importe quel DNS, ce dernier ira faire la requête au bon endroit.

Si pas de retour, l’IP n’est pas blacklisté, si retour, IP blacklisté donc.

 

2 – Contrôle profond

Très efficace contre les « lourds » qui ne respecte pas le protocole SMTP, ces vérifications ont cependant un inconvénient comme je l’expliquais :

Ils  introduisent un Greylisting. Pour effectuer ces vérifications, Postscreen prend en charge tout la communication SMTP, mais le bougre à la fin n’est pas capable de repasser la main à Postfix.

Postscreen règle le problème très « simplement » en répondant à la fin : 450 4.3.2 Service currently unavailable et en mettant au passage le serveur en liste blanche.

Le voila le Greylisting … Un serveur SMTP bien configuré se doit de retenter l’envoi et comme il sera reconnu par Postscreen,  ce dernier passera la main à Postfix.

Ça, c’est la théorie… Les trucs configurés avec les pieds, on en voit partout et il est tout a fait possible que le SMTP distant, bien que légitime, ne retente jamais. C’est pourquoi je n’aime pas le principe du Greylisting.

A vous de voir comme vous le sentez …

a – Pipelining

Postscreen ne gérant pas le pipelining (du full duplex en quelque sorte), il l’indique durant la communication. Un client « correct » le prendra alors en compte. Un « lourd », certainement que non, et bam !

postscreen_pipelining_enable = yes

postscreen_pipelining_action = enforce

 

b – Non SMTP Command

Contrôle sur d’éventuelles commandes CONNECT, GET et POST utilisées par les « lourds » passant par des proxys.

postscreen_non_smtp_command_enable = yes

postscreen_non_smtp_command_action = enforce

 

c – Bare Newline

La norme SMTP impose que chaque ligne se terminer par <CR><LF>. Les « lourds », souvent, n’utilisent que <LF>.

postscreen_bare_newline_enable = yes

postscreen_bare_newline_action = enforce

 

III – Conclusion

Voila pour ces petits ajouts à Postfix. Ils sont simples, mais efficaces comme vous pouvez le voir.

Avec tout le travail abattu jusque la, Rspamd que l’on va maintenant installer dans la partie VI va se sentir léger.

Rspamd

I – Installation

Le paquet Rspamd disponible dans les dépôts de Debian n’étant plus maintenu, on va passer par les dépôts de Rspamd

# wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add -

La, si un message évoque un problème de certificats, c’est que le paquet ca-certificates n’est pas présent.

# echo "deb [arch=amd64] http://rspamd.com/apt-stable/ stretch main" > /etc/apt/sources.list.d/rspamd.list

# apt-get update

# apt-get install rspamd

Pour fonctionner, Rspamd a besoin d’un serveur redis. Perso, j’ai une VM dédiée à cela, mais ici, on va l’installer sur le serveur mail.

# apt-get install redis-server

Nous verrons dans un article plus tard l’installation d’un serveur redis « général ».

II – Configuration

A – Assistant

Pour la configuration initiale, un assistant est disponible, ne nous en privons pas :

# rspamadm configwizard

Puis répondez :

Do you wish to continue?[Y/n]: -> Yes

Controller password is not set, do you want to set one?[Y/n]: -> Yes (et vous le renseignez)

Do you wish to set Redis servers?[Y/n]: -> Yes

Input read only servers separated by `,` [default: localhost]: (si server Redis sur un autre serveur, vous indiquez son ip.)

Input write only servers separated by `,` [default: localhost]: (idem)

Do you have any password set for your Redis?[y/N]: si y'a un pass, vous l'indiquez

Do you have any specific database for your Redis?[y/N]: s'il faut spécifier une base (dans le cas d'un redis central), vous la spécifiez aussi

Do you want to setup dkim signing feature?[y/N]: -> No (on le fera après)

Expire time for new tokens [100d]: on laisse par défaut.

Reset previous data?[y/N]: -> No, vu qu'il n'y en a pas

Do you wish to convert them to Redis?[Y/n]: -> Yes

Et on termine en rechargeant :

# service rspamd reload

 

B – Quelques ajustements

Au niveau de la configuration, tout se passe dans /etc/rspamd/, cependant, modifier ces fichiers n’est pas une bonne idée car comme indiqué dedans, ils se retrouveraient écrasés en cas d’update. On va donc utiliser le répertoire /etc/rspamd/local.d pour y indiquer nos modifications.

1 – classifier-bayes.conf

Ce fichier est créé par l’assistant, il suffit de rajouter la première ligne

autolearn = true;

backend = "redis";

new_schema = true;

expire = 8640000;

2 – worker-controller.inc

Fichier également créé par l’assistant. Ici, on rajoute les deux lignes pour les sockets. Le socket sur le port 11334 sera pour l’interface Web (c’est pour cela qu’on le bind sur l’ip interne de la machine et non sur localhost). Le second socket servira pour l’apprentissage des spams.

password = trucavous

bind_socket = "ip.interne:11334";

bind_socket = "/var/run/rspamd/rspamd.sock mode=0666 owner=nobody";

3  – metrics.conf

Fichier à créer. Il permet d’indiquer vos valeurs pour les différentes actions.

actions {

add_header = 5;

greylist = 25;

reject = 50;

}

A vous de bien régler ces paramètres. Ici, le reject est volontairement haut, dans un but de test et pour pouvoir le baisser au fur et à mesure.

4 – milter_headers.conf

Ce fichier est à créer. Il indique d’ajouter des entêtes dans les mails. Grace à eux, vous pourrez voir directement dans votre logiciel ce qui a provoqué ou non le marquage en spam. Mettez simplement :

extended_spam_headers = true;

5 – rspamd_update.conf

Dernier fichier à créer. Permet à Rspamd de se mettre à jour automatiquement au niveau des règles. On l’active, tout simplement :

enabled = true;

Et voila pour la configuration de Rspamd. Il existe d’autres modules, mais nous en parlerons dans un futur article ou nous approfondirons le sujet sur Rspamd.

III – Liaison avec Postfix

Pour dire à Postfix de passer le mail à Rspamd, c’est le protocole milter que l’on va utiliser en indiquant en bas de notre fichier /etc/postfix/main.cf :

milter_protocol = 6

milter_default_action = accept

smtpd_milters = inet:localhost:11332

non_smtpd_milters=inet:localhost:11332

milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}

Le milter_default_action spécifie l’action par défaut au cas ou Rspamd ne serait pas disponible. On recharge :

# postfix reload

# service rspamd restart

 

IV – Apprentissage

Pour l’utilisation de Rspamd au quotidien, pas grand chose à faire. C’est automatique, même pour les mises à jour. Cependant, si vous avez déjà un corpus de spam et de ham à lui apprendre, ce n’est pas une mauvaise chose de commencer par la, le filtre bayésien ne fonctionnant pas à moins de 200 mails appris par catégorie. Pour se faire, j’ai toujours deux dossiers récents de spams et de hams que je garde sous le coude. Je les déplace dans ma bal dans deux répertoires. Puis pour le spam :

# rspamc -h /var/run/rspamd/rspamd.sock learn_spam /home/vmail/domaine1.fr/toto/mailbox/.Spamtolearn/

et pour le ham :

# rspamc -h /var/run/rspamd/rspamd.sock learn_ham /home/vmail/domaine1.fr/toto/mailbox/.Hamtolearn/

Pour regarder ensuite les statistiques et voir à combien on en est :

# rspamc -h /var/run/rspamd/rspamd.sock stat

Pour un bon apprentissage, il faut lui apprendre des spams certes, mais également des hams, c’est important.

V – Apprentissage par déplacement.

Couplé avec Dovecot, Rspamd nous propose de pouvoir apprendre également en fonction des actions des utilisateurs. Si un mail est déplacé vers le répertoire spam, il sera appris comme tel et au contraire,  s’il est sorti du répertoire Spam vers autre chose que la corbeille, il sera appris comme Ham. Dans le fichier /etc/dovecot/conf.d/90-sieve-extprograms.conf, mettez cela :

plugin {

sieve_plugins = sieve_imapsieve sieve_extprograms

 

imapsieve_mailbox1_name = Junk

imapsieve_mailbox1_causes = COPY

imapsieve_mailbox1_before = file:/etc/dovecot/sieve/report-spam.sieve

 

imapsieve_mailbox2_name = *

imapsieve_mailbox2_from = Junk

imapsieve_mailbox2_causes = COPY

imapsieve_mailbox2_before = file:/etc/dovecot/sieve/report-ham.sieve

 

sieve_pipe_bin_dir = /etc/dovecot/sieve

 

sieve_global_extensions = +vnd.dovecot.pipe

}

On recharge Dovecot :

# dovecot reload

Quand un mail sera déplacé dans le répertoire Junk (Spam), le filtre report-spam.sieve sera appelé. Quand un mail sera déplacé depuis le répertoire Junk vers un autre répertoire (autre que la Corbeille), le filtre report-ham.sieve sera appelé. On va créer les filtre sieves. On créer un répertoire :

# mkdir /etc/dovecto/sieve/

Puis un fichier /etc/dovecot/sieve/report-spam.sieve :

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];

 

if environment :matches "imap.email" "*" {

set "email" "${1}";

}

 

pipe :copy "train-spam.sh" [ "${email}" ];

puis, /etc/dovecot/sieve/report-spam.sieve :

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];

 

if environment :matches "imap.mailbox" "*" {

set "mailbox" "${1}";

}

 

if string "${mailbox}" "Trash" {

stop;

}

 

if environment :matches "imap.email" "*" {

set "email" "${1}";

}

 

pipe :copy "train-ham.sh" [ "${email}" ];

On les compile :

# sievec report-ham.sieve

# sievec report-spam.sieve

Puis on change l’user :

# chown vmail:vmail report-*

On va passer à la création de nos deux petits scripts : Tout d’abord /etc/dovecot/sieve/train-ham.sh :

exec /usr/bin/rspamc -h /var/run/rspamd/rspamd.sock learn_ham

et /etc/dovecot/sieve/train-spam.sh :

exec /usr/bin/rspamc -h /var/run/rspamd/rspamd.sock learn_spam

Et on leur donne les droits :

# chown vmail:vmail train-*

# chmod +x train-*

On recharge Dovecot :

# dovecot reload

Et voila, vous pouvez vérifier en déplaçant un spam ou un ham et voir dans les fichiers de logs : Fichier /var/log/mail.log :

mail dovecot: imap(toto@domaine1.fr): sieve: pipe action: piped message to program `train-spam.sh'

Fichier /var/log/rspamd/rspamd.log :

#9159(controller) <e6896a>; csession; rspamd_controller_check_password: allow unauthorized connection from a unix socket

#9159(controller) <e6896a>; csession; rspamd_message_parse: loaded message; id: <004801d4dc01$02b7a725$5d7532ac$@lourd.com>; queue-id: <undef>; size: 1732; checksum: <b32bcf8d811d92610d2808ce822930dc>

#9159(controller) <e6896a>; csession; rspamd_mime_text_part_utf8_convert: converted from IBM852 to UTF-8 inlen: 104, outlen: 104 (104 UTF16 chars)

#9159(controller) <e6896a>; csession; rspamd_controller_learn_fin_task: </var/run/rspamd/rspamd.sock> learned message as spam: 004801d4dc01$02b7a725$5d7532ac$@lourd.com

Voila une affaire qui roule.

VI – Signature DKIM

Si jusque la, vous utilisiez Opendkim, vous pouvez l’oublier: Rspamd peut se charger de cette tâche, autant s’éviter une pièce de plus dans notre puzzle.

A – Configuration

On va tout d’abord créer le répertoire qui va accueillir nos clés :

# mkdir /var/lib/rspamd/dkim

Créez un fichier /etc/rspamd/local.d/dkim_signing.conf et ajoutez :

path = "/var/lib/rspamd/dkim/dkim.$domain.key";

allow_username_mismatch = true;

B – Signature d’un domaine

Pour signer un nouveau domaine :

# rspamadm dkim_keygen -b 2048 -s dkim -d domaine1.fr -k /var/lib/rspamd/dkim/dkim.domaine1.fr.key | tee -a /var/lib/rspamd/dkim/dkim.domaine1.fr.pub

Gardez la clé publique sous le coude, on la rajoutera dans le DNS dans la partie VII. Pour info, il est tout a fait possible d’avoir des sélecteurs différents, soit en fonction des domaines, soit pour versionner, etc… Dans ce cas, il faudrait renseigner le fichier /etc/rspamd/local.d/dkim_signing.conf de la sorte :

path = "/var/lib/rspamd/dkim/$selector.$domain.key";

selector_map = "/etc/rspamd/dkim_selectors.map";

Et le fichier /etc/rspamd/dkim_selectors.map devra contenir :

domaine.fr selecteur

domaine2.fr autre_selecteur

[...]

Puis changeons les droits :

# chmod u=rw,g=r,o= /var/lib/rspamd/dkim/*

# chown _rspamd /var/lib/rspamd/dkim/*

On recharge :

# service rspamd reload

 

VII – Interface Web

Rspamd propose une interface Web. Avant de la tester, je pensais que c’était un gadget, mais après avoir vu la chose, force est de constater qu’elle est plutôt bien fichue et permet de voir l’historique des messages, ce qui a provoqué ou non leur tag, rejet… On peut aussi y modifier les valeurs de metrics, les symboles (ce qui sert à détecter un spam par rapport à un critère donné). Bref, très pratique, je vous conseille de vous en servir. C’est déjà en écoute sur le port 11334, mais on ne va pas faire le goret et ouvrir cela sur le routeur. Servez vous d’un reverse proxy (Nginx est juste parfait) et indiquez dans la configuration de votre serveur.

location /rspamd/ {

  proxy_pass http://ip.interne.mail:11334/;

  proxy_http_version 1.1;

}

Pour s’y connecter ensuite : https://www.domaine1.fr/rspamd (par exemple) et le mot de passe est celui qu’on a renseigné grâce à l’assistant.

VIII – Conclusion

Voila, Rspamd est installé et opérationnel. La configuration reste simple, mais comme déjà dit, il existe d’autres modules que l’on peut utiliser. Ce sera pour un autre article, hors de la série sur le serveur de messagerie. La configuration présentée ici est bien suffisante dans un premier temps. En attendant, si vous voulez en savoir plus, la documentation officielle est ici : https://rspamd.com/doc/ On va passer à la finalisation de notre architecture mail avec, dans la partie VII, la mise en place des enregistrements SPF, DKIM et DMARC dans notre DNS.

DKIM, SPF et DMARC

Dans l’idéal, vous gérez vous même votre DNS, sinon, faites les modifications indiquées dans l’interface de votre registar.

Ces trois enregistrements s’appuient sur de simples champss TXT, afin que tous les resolvers les comprennent.

Il fut un temps ou on trouvait un champ SPF mais celui ci a été abandonné car pas vraiment de RFC pour cela. Il est conseillé maintenant de ne faire qu’un enregistrement TXT.

Bref, c’est tout simple, mais c’est vital, du moins, pour votre système de messagerie !

I – SPF

Cet enregistrement va stipuler une ou plusieurs IP(s) que l’ont autorise à envoyer des mails en notre nom.

Dans votre fichier de zone, indiquez :

domaine1.fr. IN TXT "v=spf1 ip4:ipserveurmail mx -all"

On indique d’accepter les mails venant de notre IP et de refuser strictement les autres.

 

II – DKIM

Cet enregistrement indique la clé publique correspondant à la clé privée utilisée par Rspamd pour signer les mails.

Un serveur distant pourra alors vérifier l’authenticité du mail en vérifiant si la clé privée utilisée pour la signature correspond à la clé publique publiée dans le DNS.

 

Reprenez la clé publique que vous aviez gardé sous le coude dans la partie VI :

dkim._domainkey IN TXT ( "v=DKIM1; k=rsa; "

"p=plein de caracteres eventuellement sur plusieurs lignes" ) ;

Insérez tout cela dans votre fichier de zone, tout simplement.

 

III – DMARC

Ce n’est pas à proprement parlé un système de protection, mais plus une façon de dire ce qu’il faut faire avec des mails qui ne passe pas votre politique SPF et/ou DKIM.

Une consigne pour le SMTP qui reçoit en quelque sorte. A ne pas négliger, car l’absence de ce champ peut compromettre la livraison de vos mails.

Insérez une ligne semblable à la suivante :

_dmarc.domaine1.fr. IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@domaine1.fr;ruf=mailto:postmaster@domaine1.fr"

le p indique la politique à appliquer chez le SMTP si un mail reçu en votre nom (de domaine) ne passe ni SPF,  ni DKIM.

Il est possible de spécifier :

rua indique à quelle adresse recevoir les reports agrégés, ruf indique où recevoir les reports détaillés (envoyés à chaque fois qu’un mail en votre nom est refusé)

Pour plus d’informations : https://dmarc.org/wiki

Au début, disons le premier mois, utilisez un p=none et une fois qu’on voit que tout est OK (les mails refusés le sont à juste titre et non pas du à une boulette de votre côté), vous pouvez passer sur p=quarantine, ou p=reject.

 

Bien sur, une fois ces ajouts faits, on pense à incrémenter le sérial du fichier de zone, puis on recharge bind :

# rndc reload

 

IV – Tests

Pour tester, on va utiliser dig et au passage, l’interrogation se fera auprès du DNS de Google pour être sur que la propagation DNS est bonne.

# dig domaine1.fr TXT @8.8.4.4 +short

Va vous renvoyer les enregistrements TXT, dont le SPF.

# dig dkim._domainkey.domaine1.fr TXT @8.8.4.4 +short

Va vous renvoyer votre DKIM.

# dig _dmarc.debugo.fr TXT @8.8.4.4 +short

Bah, le Dmarc hein…

On peut aussi utiliser des outils en ligne : http://www.appmaildev.com, https://mxtoolbox.com, etc…Il en existe plein d’autres…

 

V – Conclusion

Bah voila, ce n’était pas la partie la plus compliquée, mais à partir de maintenant, vous pouvez envoyer des messages en étant clean et reconnu par vos pairs !

Il existe aussi le système ARC, mais nous en parlerons dans un article complémentaire.

 

Et voila, plus qu’à faire une petite conclusion générale et on en aura fini avec notre serveur de mails.

Conclusion

Et bien voila, on y est. On a enfin terminé de toute mettre en place : Posfix, Dovecot, Rspamd, etc.. tout tourne de concert sans anicroches.

Cependant, quelques derniers conseils…

I – Filtre Sieve

Dans la partie II, j’active dans la configuration de Postfix les notifications au postmaster (qui est un alias de ma bal principale)

Du coup, pour les ranger proprement, j’utilise un filtre sieve :

if header :contains "subject" "Postfix SMTP server"

{

fileinto "Serveur";

}

De la sorte, je vois les erreurs (dans un dossier à part, pour ne pas polluer ma boite de réception) et peut y remédier (la plus part du temps, ce sont des lourds à bloquer définitivement dans le FW).

 

II – DNSBL

Ensuite, il peut être utile de vérifier de temps à autres si vous n’êtes pas en liste noire sur une des nombreuses DNSBL.

Il existe de nombreux sites ou script qui permettent de faire cette vérification.

Si vous vous retrouvez listé, chaque liste gérant la chose à sa façon, à vous d’aller voir sur leur site pour vous faire délister.

 

III – Liens

Voila quelques liens pour tester un peu votre serveur :

https://www.mail-tester.com : très pratique, permet de voir si vous n’auriez pas louper une étape en vous donnant une note.

https://www.emailsecuritycheck.net : teste la protection de votre système en envoyant 7 mails douteux. Le 3 ne doit même pas arriver, les autres doivent se retrouver en spam.

Plus généralement, le site https://mxtoolbox.com est très complet car il couvre de nombreuses vérifications (et pas qu’au sujet de la messagerie).

Bien évidement, la aussi, il y a pléthore de sites….

 

IV – Articles à venir

La messagerie est un sujet vaste et bien sur, je n’ai pas forcement approfondi certains points (j’avoue, je commence à saturer sur la partie messagerie 😉 )

Cependant, j’y reviendrais un peu plus tard.

Du coup, nous verrons :

Bref, restez à l’écoute !

Fail2ban, configuration pour Postfix et Dovecot

Les boulets qui tentent de se connecter à un de vos services, ca peut vite devenir…. pénible.

Avec les fuites de mot de passe qu’on retrouve un peu partout, n’importe qui ou presque peut maintenant faire le Jean-Kevin (mes excuses si un de mes lecteurs s’appelle Jean-Kevin, faudra que je parle à ses parents ceci dit..)

Bref, trêve de plaisanteries, et attaquons nous à ces petits malandrins qui n’ont rien d’autres à faire que de remplir nos fichiers de logs….

Comme on vient de terminer l’installation du serveur de messagerie, on va justement filtrer un peu les tentatives de login infructueuses sur l’IMAP et sur le SMTP.

I – Présentation et installation

Au niveau de son fonctionnement, Fail2ban est simple à comprendre.

Tout d’abord, on a des jails, c’est à dire une configuration que l’on créé et qui va s’occuper de surveiller un service en regardant ses logs. Ce sera dans le répertoire /etc/fail2ban/jail.d/.

Pour se faire, il faut savoir quoi chercher de suspect, c’est le rôle des filtres…. La, dans /etc/fail2ban/filter.d/, on en trouve déjà beaucoup de proposés. Bien sur, on pourra faire les siens.

Et ensuite, il faut dire ce qu’on fait avec les lourds que l’on trouve dans les logs après filtrage : ce sont les actions. La aussi, dans /etc/fail2ban/action.d/ on en trouve, et la aussi on pourra faire les nôtres.

Pour l’installation, rien de compliqué :

# apt-get install fail2ban

 

II – Configuration

Maintenant, il s’agit de créer les jails. On va en faire une pour Postfix, puis une pour Dovecot

A – Postfix

Dans un fichier /etc/fail2ban/jail.d/postfix.conf, mettez ceci :

[postfix-sasl]

enabled = true

filter = postfix-sasl

action = iptables-allports

         mail[name=Postfix SASL]

bantime = 3600

maxretry = 2

logpath = /var/log/mail.log

Au niveau du filtre, on se sert de celui qui existe déjà, et au niveau action, on utilise celle qui bloque tout au niveau du FW plus un p’tit mail d’info.

On active le ban au bout de deux tentatives et ce pour une heure.

 

B – Dovecot

Dans un fichier /etc/fail2ban/jail.d/dovecot.conf, mettez ceci :

[dovecot]

enabled = true

filter = dovecot

action = iptables-allports

         mail[name=Dovecot]

bantime = 3600

maxretry = 2

logpath = /var/log/mail.log

La, on utilise le filtre dovecot déjà existant et le reste, comme Postfix…

 

IV – Test

Ne reste plus qu’à recharger :

# service fail2ban reload

Puis, on peut déjà regarder le log voir si tout est OK :

# tail /var/log/fail2ban.log -f

On peut aussi en savoir plus sur les jails en cours :

# fail2ban-client status

Puis le détail :

# fail2ban-client status postfix-sasl

Pour bannir de force par exemple :

# fail2ban-client set postfix-sasl banip XXX.XXX.XXX.XXX

etc….

Après, il n’y a plus qu’à attendre pour voir si cela marche bien, et généralement, ça ne prend pas trop de temps.

 

V – Conclusion

Et voila, vous voyez, c’est très simple et ça marche… mais ceci dit, je n’aime pas car chaque serveur aura alors ses propres règles de blocages.

Et perso, si un lourd est lourd sur un service, je ne vois pas pourquoi il ne le serait pas sur un autre, ce serait donc mieux de le bloquer en amont, avec le firewall du routeur.

Et bien, cela tombe bien, c’est ce qu’on va voir dans l’article suivant avec la mise en place d’un système client-serveur en python.

Fail2ban et python pour piloter un Firewall central

Précédemment, nous avons vu Fail2ban configuré pour Dovecot et Postfix, mais l’inconvénient de la solution proposée dans une architecture de serveurs derrière un routeur, c’est que pour le coup, chaque serveur aura ses propres règles de blocage.

J’aimerais bien centraliser tout. Si un boulet se présente sur le serveur mail, autant le bloquer sur tout et ce, dès son arrivée sur mon routeur…

Du coup, il faut trouver le moyen de faire le blocage directement dans le firewall de ce dernier. Quid ?

Installer fail2ban sur le routeur ? Pourquoi pas, mais il lui faudrait donc la possibilité de lire les logs des autres VMS…

Des partages NFS ? Non…

Rapatrier les logs sur le routeur pour que fail2ban fasse son taf ? Bof, mon routeur n’a pas pour vocation de centraliser les logs…

Hum… Fail2ban sur le routeur n’est pas la solution.

Le truc serait de garder fail2ban sur chaque machine avec ses logs et sa config et de piloter le firewall du routeur…

En voila une bonne idée !

Pour cela, on va passer par un truc que j’affectionne, un petit système client-serveur en python. C’est rapide à mettre en place et ça répond parfaitement à mon problème.

Sur le routeur, un serveur en écoute des instructions des clients pour modifier le firewall. Et sur chaque serveur, un client  actionné par fail2ban pour balancer l’ordre.

Simple non ?

II – Sur le routeur

A – De nouvelles chaines

Sur le firewall, on va déjà préparer le terrain et créant des chaines spécifiques.

Je pars du principe que vous utilisez un fichier pour les règles du firewall. On va dire qu’il s’appelle firewall.sh.

Donc, dans firewall.sh, après :

#!/bin/bash

 

iptables -t filter -F

iptables -t filter -X

iptables -t nat -F

iptables -t nat -X

iptables -t mangle -F

iptables -t mangle -X

Ajoutez :

# creation des chaines

iptables -N f2b-postfix

iptables -N f2b-dovecot

# on ajoute un retour dans ces chaines (pour revenir à INPUT ou FORWARD, selon le cas)

iptables -A f2b-postfix -j RETURN

iptables -A f2b-dovecot -j RETURN

# Puis on indique dans INPUT et FORWARD de traverser les nouvelles chaines.

iptables -I INPUT -j f2b-postfix

iptables -I INPUT -j f2b-dovevot

iptables -I FORWARD -j f2b-postfix

iptables -I FORWARD -j f2b-dovecot

 

[...]

On reprend le concept qu’utilise Fail2ban par défaut, à savoir créer une nouvelle chaine, puis faire passer les flux dedans. Si rien ne bloque, ça revient dans les chaines INPUT ou FORWARD (en fonction) et passe les autres règles.

Et j’en profite pour créer une chaine par service, histoire de bien voir par la suite quel service à fait le blocage.

Au passage pensez à autoriser en INPUT sur le port que vous choisirez pour votre serveur.

iptables -t filter -A INPUT -p tcp -s 10.20.1.0/24 --dport 666 -j ACCEPT

Mon réseau interne entre les vms étant en 10.20.1.0/24

Une fois votre fichier firewall.sh ou autre modifié, on exécute :

routeur# ./firewall.sh

 

B – Serveur Python

Maintenant, on va créer le serveur python qui va écouter les ordres des autres VMS, et appliquer les règles.

On installe python :

routeur# apt-get install python

Puis dans un fichier : /srv/pyban.py, vous copiez cela :

#!/usr/bin/env python

 

import socket

import os

import threading

 

class ClientThread(threading.Thread):

    def __init__(self, ip, port, clientsocket):

        threading.Thread.__init__(self)

        self.ip = ip

        self.port = port

        self.clientsocket = clientsocket

 

    def run(self):

        r = self.clientsocket.recv(1024)

        item = r.split(":")

        if item[0] == "ban":

            chain = "iptables -I "+item[2]+" -s "+item[1]+" -j DROP"

            os.system(chain)

        if item[0] == "unban":

            chain = "iptables -D "+item[2]+" -s "+item[1]+" -j DROP"

            os.system(chain)

        else:

            error = 1

 

tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

tcpsock.bind(("XXX.XXX.XXX.XXX",666))

 

while True:

    tcpsock.listen(5)

    (clientsocket, (ip, port)) = tcpsock.accept()

    newthread = ClientThread(ip, port, clientsocket)

    newthread.start()

 

tcpsock.close()

Tout simple, on a un serveur qui écoute sur le port 666, avec la gestion du multithread, ca ne coute rien.

Il attend comme paramètres ce qu’il faut faire (ban ou unban), l’ip et la chaine dans laquelle on se place.

Pensez bien sur à remplacer XXX.XXX.XXX.XXX par l’ip interne du routeur (par exemple, 10.20.1.1; pas de localhost car sinon, les clients ne pourraient le joindre…)

On peut déjà tester si cela tourne sans erreur :

# python /srv/pyban.py

Ctrl+C pour arrêter.

C – Service

Maintenant, on va en faire un service, histoire qu’il se lance tout seul et soit autonome.

Créez un fichier /etc/systemd/system/pyban.service et mettez y :

Description=Server Python Ban

After=network-online.target

 

[Service]

Type=idle

ExecStart=/usr/bin/python /srv/pyban.py

 

[Install]

WantedBy=multi-user.target

Puis on l’active et on le démarre :

# systemctl enable pyban.service

# systemctl start pyban.service

Voila pour le routeur.

II – Sur le serveur

Pour l’exemple, je reprend mon serveur de mail.

A – Client python

Bien évidement, on installe python :

mail# apt-get install python

On va créer ensuite un fichier /srv/pybanclient.py avec dedans :

#!/usr/bin/env python

 

import socket

import sys

 

try:

    s = ":";

    seq = (sys.argv[1], sys.argv[2], sys.argv[3]);

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    sock.connect(("XXX.XXX.XXX.XXX", 666))

    sock.send(s.join(seq))

    sock.close

except(socket.error):

    sys.exit()

Bien évidement, XXX.XXX.XXX.XXX doit être remplacé par l’ip du routeur.

B – Fail2ban

1 – Action

On va créer un fichier action nommé /etc/fail2ban/action.d/pyban.conf avec ce qui suit dedans :

[Definition]

 

actionban = python /srv/pybanclient.py ban <ip> <name>

actionunban = python /srv/pybanclient.py unban <ip> <name>

2 – Jail

On va modifier nos deux jails.

Tout d’abord /etc/fail2ban/jail.d/postfix.conf :

[postfix-sasl]

enabled = true

filter = postfix-sasl

action = pyban[name=f2b-postfix]

         mail[name=Postfix SASL]

bantime = 3600

maxretry = 2

logpath = /var/log/mail.log

Puis /etc/fail2ban/jail.d/dovecot.conf :

[dovecot]

enabled = true

filter = dovecot

action = pyban[name=f2b-dovecot]

         mail[name=Dovecot]

bantime = 3600

maxretry = 2

logpath = /var/log/mail.log

Et on termine en rechargeant :

mail# service fail2ban reload

 

III – Test

Rien de plus simple.

Sur le serveur :

serveur# fail2ban-client set postfix-sasl banip XXX.XXX.XXX.XXX

Sur le routeur :

routeur# iptables -L -n

On doit voir l’ip apparaitre dans la bonne chaine avec un DROP devant .

Et si on déban sur le serveur :

serveur# fail2ban-client set postfix-sasl unbanip XXX.XXX.XXX.XXX

Ce doit être nettoyé sur le routeur :

routeur# iptables -L -n

 

iV – Conclusion

Bah voila, on a enfin notre fail2ban qui peut piloter un FW en amont afin de voir les boulets bloqués sur tous nos services. Rien de bien sorcier au final…

Par la suite, on pourra rajouter d’autres services en pilotage en rajoutant leurs règles dans le FW du routeur et avec des clients python sur les serveurs.